
package com.pig4cloud.pigx.wms.service.impl;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.pig4cloud.pigx.wms.dto.*;
import com.pig4cloud.pigx.wms.entity.*;
import com.pig4cloud.pigx.wms.service.*;
import com.pig4cloud.pigx.wms.vo.*;
import com.pig4cloud.pigx.wms.webtools.Constants;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.pig4cloud.pigx.common.security.util.SecurityUtils;
import com.pig4cloud.pigx.wms.mapper.InStorageMapper;
import com.pig4cloud.pigx.wms.mapper.WcsWmsTrxMapper;
import com.pig4cloud.pigx.wms.mapper.OutStorageMapper;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * 出库service实现类
 *
 * @author gaoxin
 * @date 2021-04-13 14:48:32
 */
@Service
@RefreshScope
@RequiredArgsConstructor
@Slf4j
public class OutStorageServiceImpl extends ServiceImpl<OutStorageMapper, OutStorage> implements OutStorageService {

	private final OutStorageItemService outStorageItemService;

	private final OutStorageTpService outStorageTpService;

	private final SLocationService sLocationService;

	private final TraySkuService traySkuService;

	private final AgvInQueueService agvInQueueService;

	private final AgvOutQueueService agvOutQueueService;

	private final InStorageItemService inStorageItemService;

	private final InStorageMapper inStorageMapper;

	private final B2bTaskRecordService b2bTaskRecordService;

	private final BhTMPService bhTMPService;

	private final SkuService skuService;

	private final WcsWmsTrxService wcsWmsTrxService;

	private final WcsWmsTrxMapper wcsWmsTrxMapper;

	private final SubPackageService subPackageService;

	private final SubPackageInfoService subPackageInfoService;

	private final SCartService sCartService;

	private final CartInfoService cartInfoService;

	private final ERPCallBackService erpCallBackService;

	private final StockAreaService stockAreaService;

	private final InStorageService inStorageService;

	private final ERPCheckFeedbackService erpCheckFeedbackService;

	@Value("${ds.dpg.limit}")
	private int ds_limit;

	@Value("${ds.larea.quantity}")
	private double lQuantity;

	@Value("${ds.cart.quantity}")
	private int cartQuantity;

	@Value("${ds.cart.order.quantity}")
	private int cartOrderQuantity;

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void saveALLCX(ERPOutStorageDTO erpOutStorageDTO) {

		saveOut(erpOutStorageDTO, "CKA");

	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void handleDSOuts(JSONObject jsonObject) {

		JSONArray jsonArray = jsonObject.getJSONArray("deliverys");

		List<ERPOutStorageDTO> erpOutStorageDTOS = new ArrayList<>();

		for(JSONObject outjsonObject : jsonArray.toList(JSONObject.class)){

			if(this.getById(outjsonObject.getStr("code")) != null){

				log.info("此管易出库单已经存在,处理下一个...");
				continue;

			}

			ERPOutStorageDTO erpOutStorageDTO = new ERPOutStorageDTO();
			erpOutStorageDTO.setOutPageNo(outjsonObject.getStr("code"));
			erpOutStorageDTO.setStorageId(1);
			erpOutStorageDTO.setHuozId("1001");
			erpOutStorageDTO.setWlzxCode("6001");
			erpOutStorageDTO.setOutType("2");
			erpOutStorageDTO.setLocationNo("DSCK100001");

			JSONArray itemJsonArray = outjsonObject.getJSONArray("details");

			List<ERPOutStorageItemDTO> erpOutStorageItemDTOS = new ArrayList<>();

			for(JSONObject itemJsonObject : itemJsonArray.toList(JSONObject.class)){

				ERPOutStorageItemDTO erpOutStorageItemDTO = new ERPOutStorageItemDTO();
				erpOutStorageItemDTO.setSku(itemJsonObject.getStr("item_code"));
				erpOutStorageItemDTO.setAmount(itemJsonObject.getInt("qty"));

				erpOutStorageItemDTOS.add(erpOutStorageItemDTO);

			}

			erpOutStorageDTO.setErpOutStorageItemDTOList(erpOutStorageItemDTOS);
			erpOutStorageDTOS.add(erpOutStorageDTO);
		}

		this.saveALLGY(erpOutStorageDTOS);
	}

	private void saveOut(ERPOutStorageDTO erpOutStorageDTO, String cka) {

		OutStorage outStorage = this.getById(erpOutStorageDTO.getOutPageNo());


		if(outStorage != null){

			//出库单如果有波次号的话,抛出异常不能更新出库单
			if(StringUtils.isNotEmpty(outStorage.getPackageNo())){

				log.error("此发货单已经进入波次无法更新,出库单号是:"+outStorage.getWmsBillNo());

				throw new RuntimeException("此发货单已经进入波次无法更新,出库单号是:"+outStorage.getWmsBillNo());

			}

			//只有未出库状态才允许更新
			if(!"0".equals(outStorage.getStatus())){

				log.error("此发货单不是未出库状态,无法更新,出库单号是:"+outStorage.getWmsBillNo());

				throw new RuntimeException("此发货单不是未出库状态,无法更新,出库单号是:"+outStorage.getWmsBillNo());

			}

			//出库单存在的时候 删除相关行项目重新创建
				outStorageItemService.remove(Wrappers.<OutStorageItem>query().lambda().eq(OutStorageItem::getWmsBillNo
						,outStorage.getWmsBillNo()));
				outStorage.setStatus("0");
				log.info("出库单存在，更新出库单头信息，删除行信息并重置出库单状态为未出库 出库单号:"+outStorage.getWmsBillNo());

		}else{
			outStorage = new OutStorage();
		}

		BeanUtils.copyProperties(erpOutStorageDTO, outStorage);

		String outDateStr = erpOutStorageDTO.getOutDate();
		DateTimeFormatter dtFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
		LocalDateTime outDateLD = LocalDateTime.parse(outDateStr, dtFormatter);

		outStorage.setOutDate(outDateLD);

		LocalDateTime timeNow = LocalDateTime.now();

		DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");

		String ymdhms = dtf.format(timeNow);

		int randomInt = RandomUtil.randomInt(1000, 9999);

		String preWmsNo = cka;

		String wmsNO = preWmsNo + ymdhms + randomInt;

		outStorage.setWmsBillNo(wmsNO);

		if (erpOutStorageDTO.getErpOutStorageItemDTOList().size() > 1) {
			outStorage.setIsOneItem("0");
		}

		this.saveOrUpdate(outStorage);
		log.info("创建或更新出库单《出库单号:"+outStorage.getWmsBillNo());

		List<ERPOutStorageItemDTO> erpOutStorageItemDTOList = erpOutStorageDTO.getErpOutStorageItemDTOList();

		for (int i = 0; i < erpOutStorageItemDTOList.size(); i++) {

			OutStorageItem outStorageItem = new OutStorageItem();

			ERPOutStorageItemDTO erpOutStorageItemDTO = erpOutStorageItemDTOList.get(i);

			BeanUtils.copyProperties(erpOutStorageItemDTO, outStorageItem);

			outStorageItem.setWmsBillNo(wmsNO);

			outStorageItem.setWmsItemNo(wmsNO + "_" + i);

			outStorageItemService.save(outStorageItem);

		}
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void saveALLGY(List<ERPOutStorageDTO> erpOutStorageDTOs) {

		for(ERPOutStorageDTO erpOutStorageDTO : erpOutStorageDTOs){

			saveOut(erpOutStorageDTO, "CKC");

		}

	}

	@Override
	public IPage<OutStoragePageVO> getOutStoragePageForVO(Page page, OutStoragePageDTO outStoragePageDTO) {
		return baseMapper.getOutStoragePageForVO(page, outStoragePageDTO);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public synchronized CreatePackageReturnDTO createPackageOrStockUp(List<OutStorageForPackageDTO> outStorageForPackageList,
																	  String method, String bhlx) {

		// 计算波次下发耗时 开始时间
		long stime = System.currentTimeMillis();

		CreatePackageReturnDTO createPackageReturnDTO = new CreatePackageReturnDTO();
		createPackageReturnDTO.setSuccess(true);

		//校验状态
		for(OutStorageForPackageDTO outStorageForPackageDTO : outStorageForPackageList){

			//检查出库单有没有出库位置
			OutStorage outStorage = this.getById(outStorageForPackageDTO.getOutStorageId());

			if(StringUtils.isEmpty(outStorage.getLocationNo())){

				createPackageReturnDTO.setSuccess(false);
				createPackageReturnDTO.setMessage("出库单:"+outStorageForPackageDTO.getOutStorageId()+"没有出库位置,创建波次/备货失败.");
				return createPackageReturnDTO;

			}

			//查找立库区出库位置
//			SLocation sLocation =
//					sLocationService.getOne(Wrappers.<SLocation>query().lambda().eq(SLocation::getAreaId,"7").eq(SLocation::getIsUsed,"0")
//							.eq(SLocation::getLocationStatus,"1").eq(SLocation::getStatus,"1").eq(SLocation::getSLocationNo,outStorage.getLocationNo())
//							.orderByAsc(SLocation::getSOrder).last("limit 1"));
//
//			if(null == sLocation){
//
//				createPackageReturnDTO.setSuccess(false);
//				createPackageReturnDTO.setMessage("出库单:"+outStorageForPackageDTO.getOutStorageId()+"出库位置非法,创建波次失败"
//						+ ".出库位置是:"+outStorage.getLocationNo());
//				return createPackageReturnDTO;
//
//			}

			if(!"0".equals(outStorageForPackageDTO.getStatus())){

				createPackageReturnDTO.setSuccess(false);
				createPackageReturnDTO.setMessage("出库单:"+outStorageForPackageDTO.getOutStorageId()+"状态不对,创建波次/备货失败.");
				return createPackageReturnDTO;
			}

		}

		List<String> chanxianOuts = new ArrayList<>();
		List<String> toCOuts = new ArrayList<>();
		List<String> dianshangOuts = new ArrayList<>();

     	//出库单分组
		for(OutStorageForPackageDTO outStorageForPackageDTO : outStorageForPackageList){

			if("2".equals(outStorageForPackageDTO.getOutType())){
				dianshangOuts.add(outStorageForPackageDTO.getOutStorageId());
			}else if("1".equals(outStorageForPackageDTO.getOutType())){
				chanxianOuts.add(outStorageForPackageDTO.getOutStorageId());
			}else if("3".equals(outStorageForPackageDTO.getOutType())){
				toCOuts.add(outStorageForPackageDTO.getOutStorageId());
			}else{

				createPackageReturnDTO.setSuccess(false);
				createPackageReturnDTO.setMessage("出库单:"+outStorageForPackageDTO.getOutStorageId()+"类型不对,创建波次/备货失败"
						+ ".");
				return createPackageReturnDTO;
			}
		}

//		String isOneFlag = null;
//		//检查电商订单是否符合出库规则，单品规和多品规不能混合，单品规不限订单数量，多品规订单上线ds.dpg.limit单
//		for(String dsOrder:dianshangOuts){
//
//			OutStorage outStorage = this.getById(dsOrder);
//			String isOneItem = outStorage.getIsOneItem();
//
//			if(isOneFlag == null){
//				isOneFlag = isOneItem;
//
//			}else{
//				if(!isOneFlag.equals(outStorage.getIsOneItem())){
//
//					createPackageReturnDTO.setSuccess(false);
//					createPackageReturnDTO.setMessage("电商出库单单品规和多品规出现混合，创建波次失败...");
//					return createPackageReturnDTO;
//
//				}
//			}
//
//		}
//		log.info("波次下发中电商订单类型是 单品规为1 多品规为0. 标识是"+isOneFlag+",电商出库单数量是:"+dianshangOuts.size() );
//
//		if("0".equals(isOneFlag)){
//
//			if(dianshangOuts.size() > ds_limit){
//
//				createPackageReturnDTO.setSuccess(false);
//				createPackageReturnDTO.setMessage("电商出库单多品规数量超出限定值，创建波次失败...");
//				return createPackageReturnDTO;
//
//			}
//
//		}

		//检查库存并创建波次
		if(chanxianOuts.size() > 0){

			handleChanXianOrB2COut(createPackageReturnDTO, chanxianOuts, method, bhlx);
		}
		if(toCOuts.size() > 0){

			handleChanXianOrB2COut(createPackageReturnDTO, toCOuts, method, bhlx);
		}
		if(dianshangOuts.size() > 0){

			List<OutStorage> outStorageList = this.list(Wrappers.<OutStorage>query().lambda()
			.eq(OutStorage::getPackageStatus,"1"));

			if(outStorageList.size() > 0){

				createPackageReturnDTO.setSuccess(false);
				createPackageReturnDTO.setMessage("已经存在电商波次单正在提总拣货,无法进行发货单波次下发...");
				return createPackageReturnDTO;

			}

			//处理电商订单
			handleDSOut(createPackageReturnDTO, dianshangOuts);
		}

		if(createPackageReturnDTO.isSuccess()){

			createPackageReturnDTO.setMessage("所有出库单成功下发波次/备货.");

		}

		// 结束时间
		long etime = System.currentTimeMillis();

		// 计算执⾏时间
		log.info("波次下发/备货执⾏时长："+(etime - stime)+" 毫秒.");

		return createPackageReturnDTO;
	}

	private void handleChanXianOrB2COut(CreatePackageReturnDTO createPackageReturnDTO, List<String> chanxianOrB2COuts,
										String method,String bhlx) {
		//保存多个wcs出库接口参数,最后用另外一个线程触发
		List<WCSInvOutDTO> wcsInvOutDTOList = new ArrayList<>();

		for(String chanxianOrB2COut : chanxianOrB2COuts){

			OutStorage outStorage = this.getById(chanxianOrB2COut);

			boolean canPackage = true;

			List<String> usedSlocation = new ArrayList<>();

			List<OutStorageItem> outStorageItemList = outStorageItemService.list(
					Wrappers.<OutStorageItem>query().lambda().eq(OutStorageItem::getWmsBillNo, outStorage.getWmsBillNo()));

			for(OutStorageItem outStorageItem : outStorageItemList){

				int outAmount = outStorageItem.getAmount();
				String sku = outStorageItem.getSku();
				//剩余出库数量
				int amountLeft = outAmount;

				//保存符合条件的库区
				List<String> stockAreaFoundNoList = new ArrayList<>();

				//保存符合条件的库位
				List<String> sLocationFoundNoList = new ArrayList<>();

				List<StockArea> stockAreaList;

				//在库区查找指定批号的sku
				if(StringUtils.isEmpty(outStorageItem.getBatchNo())){

					log.info("查找指定sku的库区，批号为空:"+outStorageItem.getBatchNo()+"sku:"+outStorageItem.getSku());
					stockAreaList = stockAreaService.list(Wrappers.<StockArea>query().lambda()
							.eq(StockArea::getAreaId, 1)
							.eq(StockArea::getSku,outStorageItem.getSku())
							//查找锁定的库区
							.eq(StockArea::getLockStatus,"1")
							//查找启用的库区
							.eq(StockArea::getActivatedStatus,"1")
							//修改为按更新时间正序获取 时间早的先出
							//.orderByAsc(StockArea::getUpdateTime));
							//.orderByAsc(StockArea::getSaOrder));
							//按batch_no正序排序
							.orderByAsc(StockArea::getBatchNo));

				}else{

					log.info("查找指定批号、sku的库区，批号:"+outStorageItem.getBatchNo()+" sku:"+outStorageItem.getSku());
					stockAreaList = stockAreaService.list(Wrappers.<StockArea>query().lambda()
							.eq(StockArea::getAreaId, 1)
							.eq(StockArea::getBatchNo, outStorageItem.getBatchNo())
							.eq(StockArea::getSku,outStorageItem.getSku())
							//查找锁定的库区
							.eq(StockArea::getLockStatus,"1")
							//查找启用的库区
							.eq(StockArea::getActivatedStatus,"1")
							.orderByAsc(StockArea::getSaOrder));
				}

				if(null == stockAreaList || stockAreaList.size() == 0){

					createPackageReturnDTO.setSuccess(false);
					createPackageReturnDTO.setMessage(" 产线出库单或To大C出库单:"+chanxianOrB2COut+
							"未找到合适的库区.原始出库单:"+outStorage.getOutPageNo()+" sku:"+outStorageItem.getSku()+
							" 批号:"+outStorageItem.getBatchNo());
					canPackage = false;
					break;

				}

				for(StockArea stockArea : stockAreaList){
					log.info("循环按顺序添加查找到符合条件的库区"+stockArea.getStockAreaNo());
					stockAreaFoundNoList.add(stockArea.getStockAreaNo());

				}

				//按照库区顺序 查找立库区的已使用的托盘加货物的激活的,外面的先出
				for(String foundStockArea : stockAreaFoundNoList){
					log.info("查找"+foundStockArea+"库区下符合条件的库位 外面先出");
					List<SLocation> sLocationList =
							sLocationService.list(Wrappers.<SLocation>query().lambda().eq(SLocation::getAreaId,"1").eq(SLocation::getIsUsed,"1")
									.eq(SLocation::getLocationStatus,"4").eq(SLocation::getStatus,"1").eq(SLocation::getSku,sku)
									.eq(SLocation::getStockAreaNo,foundStockArea)
									.orderByDesc(SLocation::getSOrder));
					for(SLocation sLocation : sLocationList){
						log.info("添加"+sLocation.getSLocationNo()+"库位，符合条件的库位 外面先出");
						sLocationFoundNoList.add(sLocation.getSLocationNo());

					}
				}

				//循环获取对应托盘库存
				for(String sLocationNo : sLocationFoundNoList){

					//查找立库区的已使用的托盘加货物的激活的
					SLocation sLocation =
							sLocationService.getOne(Wrappers.<SLocation>query().lambda().eq(SLocation::getSLocationNo
									,sLocationNo));

					if(amountLeft <= sLocation.getStockNum()){

						sLocation.setIsUsed("2");
						sLocation.setLocationStatus("1");
						sLocation.setOutAmount(amountLeft);
						sLocation.setUpdateTime(LocalDateTime.now());
						sLocationService.updateById(sLocation);
						//库存数量够,最后一托的情况把剩余库存数量置为0
						amountLeft = 0;
						usedSlocation.add(sLocation.getSLocationNo());
						saveOutTp(outStorageItem, sLocation);
						break;

					}else{
						sLocation.setIsUsed("2");
						sLocation.setLocationStatus("1");
						sLocation.setOutAmount(sLocation.getStockNum());
						sLocation.setUpdateTime(LocalDateTime.now());
						sLocationService.updateById(sLocation);
						usedSlocation.add(sLocation.getSLocationNo());
						amountLeft = amountLeft - sLocation.getStockNum();
						saveOutTp(outStorageItem, sLocation);
					}

				}

				//还有剩余数量表示库存不足
				if(amountLeft != 0){
					canPackage = false;
				}

				if(!canPackage){

					//清除发货单托盘出库信息
					outStorageTpService.remove(Wrappers.<OutStorageTp>query().lambda().eq(OutStorageTp::getWmsBillNo
							,outStorageItem.getWmsBillNo()));

					break;
				}

			}

			if(canPackage){

				//如果是波次下发执行以下逻辑
				if(method.equals(Constants.BCXF)){
					log.info("正常波次下发，每个出库单保存wcs指令对象，wcstrx对象和traysku对象，最后一起发送wcs出库指令");
					//把出库的库位信息copy到临时托盘信息中
					for(String locationNo : usedSlocation){
						SLocation sLocation = sLocationService.getById(locationNo);

						//usedSlocation中占用的库位发往wcs to出库单中的月台信息
						WCSInvOutDTO wcsInvOutDTO = new WCSInvOutDTO();
						String taskId = "wmstrx" + LocalDateTime.now()
								.format(DateTimeFormatter.ofPattern(DatePattern.PURE_DATETIME_MS_PATTERN));
						wcsInvOutDTO.setTaskId(taskId);
						wcsInvOutDTO.setInvOutType("9");
						wcsInvOutDTO.setOutLoc(locationNo);
						wcsInvOutDTO.setStockNo(sLocation.getTrayNo());
						wcsInvOutDTO.setLocDesti(outStorage.getLocationNo());
						wcsInvOutDTO.setMemoInfo1("wms调用wcs出库接口,to出库单中的月台信息");
						wcsInvOutDTO.setMemoInfo2(sLocation.getStockAreaNo());

						wcsInvOutDTOList.add(wcsInvOutDTO);

						WcsWmsTrx wcsWmsTrx = new WcsWmsTrx();
						wcsWmsTrx.setWmsTrxId(taskId);
						wcsWmsTrx.setTrxType("9");
						wcsWmsTrx.setFromLocation(locationNo);
						wcsWmsTrx.setToLocation(outStorage.getLocationNo());
						wcsWmsTrx.setTrayNo(sLocation.getTrayNo());
						wcsWmsTrxMapper.insert(wcsWmsTrx);

						TraySku traySku = new TraySku();
						BeanUtils.copyProperties(sLocation, traySku);
						traySku.setMustNum(sLocation.getOutAmount());
						traySku.setCreateTime(null);
						traySku.setUpdateTime(null);
						traySkuService.save(traySku);

					}

					//更新波次信息
					outStorage.setPackageNo("BC"+outStorage.getOutPageNo());
					outStorage.setPackageStatus("0");
					outStorage.setStatus("1");
					this.updateById(outStorage);
				}else if(method.equals(Constants.BHXF)){
					log.info("更新出库单"+chanxianOrB2COut+"为备货中。。。准备备货下发...");

					//更新备货信息
					outStorage.setStatus("6");
					this.updateById(outStorage);

				}


			}else{

				createPackageReturnDTO.setSuccess(false);
				createPackageReturnDTO.setMessage(createPackageReturnDTO.getMessage()+" 产线出库单或To大C出库单:"+chanxianOrB2COut+
						"库存不足.");

				//库存不足抛出异常
				throw new RuntimeException(createPackageReturnDTO.getMessage()+" 产线出库单或To大C出库单:"+chanxianOrB2COut+
						"库存不足.");
			}

		}

		if(method.equals(Constants.BCXF)){
			log.info("多个出库单处理完毕,启动新线程调用wcs出库接口");

			OutCallWcsThread outCallWcsThread = new OutCallWcsThread(wcsInvOutDTOList,wcsWmsTrxService);
			outCallWcsThread.start();
		}else if(method.equals(Constants.BHXF)){
			log.info("开始处理备货下发...");

			//处理备货具体逻辑
			handleStockUp(chanxianOrB2COuts,bhlx);

		}


	}

	private void handleStockUp(List<String> chanxianOrB2COuts, String bhlx) {

		if(bhlx.equals(Constants.SBH)){
			log.info("开始处理单订单备货...");
			//如果有多订单备货入库任务的时候，不允许单订单备货
			AgvInQueue agvInQueueDoing = agvInQueueService.getOne(Wrappers.<AgvInQueue>query().lambda()
					.eq(AgvInQueue::getBhlx, Constants.DBH)
					.and(tmp->tmp.eq(AgvInQueue::getQueueStatus,"0")
					.or().eq(AgvInQueue::getQueueStatus,"2"))
					.last("limit 1"));
			if(null != agvInQueueDoing){
				throw new RuntimeException("备货入库队列中存在未开始或未完成的多订单任务，不能触发单订单备货！");
			}
			//取出出库单id
			String outPageNo = chanxianOrB2COuts.get(0);

			OutStorage outStorage = this.getById(outPageNo);

			//按sku batchno 数量排序
			List<OutStorageItem> outStorageItemListForBH = outStorageItemService.list(Wrappers.<OutStorageItem>query().lambda()
					.eq(OutStorageItem::getWmsBillNo, outStorage.getWmsBillNo()).orderByAsc(OutStorageItem::getSku)
					.orderByAsc(OutStorageItem::getBatchNo).orderByAsc(OutStorageItem::getAmount));
			//出库单行项目数量小的先出
			for(OutStorageItem outStorageItem : outStorageItemListForBH){
				List<OutStorageTp> outStorageTpListForBH = outStorageTpService.list(Wrappers.<OutStorageTp>query().lambda()
						.eq(OutStorageTp::getWmsBillNo, outStorageItem.getWmsBillNo())
						.eq(OutStorageTp::getOutStorageItemId, outStorageItem.getOutStorageItemId())
						.orderByAsc(OutStorageTp::getOutStorageTpId));
				//行项目托盘从大到小出库
				for(OutStorageTp outStorageTpForBH : outStorageTpListForBH){

					SLocation sLocationFromLiKu = sLocationService.getById(outStorageTpForBH.getLocation());
					AgvInQueue agvInQueue = new AgvInQueue();
					BeanUtils.copyProperties(sLocationFromLiKu, agvInQueue);
					agvInQueue.setMustNum(sLocationFromLiKu.getOutAmount());
					//AGV目标区一个库位
					//SLocation agvSLocation = getAGVSlocation();
					//更新此库位为使用中
					//agvSLocation.setIsUsed("2");
					//sLocationService.updateById(agvSLocation);
					//agvInQueue.setAgvLocationNo(agvSLocation.getSLocationNo());
					agvInQueue.setOutPageNo(outStorage.getOutPageNo());
					agvInQueue.setOutStorageItemId(outStorageTpForBH.getOutStorageItemId());
					agvInQueue.setOutStorageTpId(outStorageTpForBH.getOutStorageTpId());
					agvInQueue.setOutLocation(outStorage.getLocationNo());
					agvInQueue.setBhlx(Constants.SBH);
					agvInQueue.setQueueStatus("0");
					agvInQueue.setCreateTime(null);
					agvInQueue.setUpdateTime(null);
					agvInQueueService.save(agvInQueue);
				}

			}
				log.info("已添加单订单备货任务到agvin队列中");

			List<OutStorageTp> outStorageTpList = outStorageTpService.list(Wrappers.<OutStorageTp>query().lambda()
					.eq(OutStorageTp::getWmsBillNo, outStorage.getWmsBillNo()));
			int outTpSize = outStorageTpList.size();

			List<SLocation> agvSlocationList = sLocationService.list(Wrappers.<SLocation>query().lambda()
					.eq(SLocation::getAreaId, 10)
					.eq(SLocation::getIsUsed, "0")
					.eq(SLocation::getStatus, "1")
					.eq(SLocation::getLocationStatus, "1"));
			int agvSize = agvSlocationList.size();

			if(agvSize > 0){
				if(agvSize >= outTpSize){
					log.info("AGV可用库位数大于单订单备货数正常备货。。。");
					log.info("从AGVin队列里取出所有此出库单任务后执行备货。。。出库单号为:"+outPageNo);
					List<AgvInQueue> agvInQueueListForUpdate = agvInQueueService.list(Wrappers.<AgvInQueue>query().lambda()
							.eq(AgvInQueue::getOutPageNo,outPageNo)
							.orderByAsc(AgvInQueue::getId));
					log.info("取出agvin队列任务"+agvInQueueListForUpdate.size()+"条 循环更新备货出库信息。。。");
					updateAGVinQueue(agvInQueueListForUpdate);

					log.info("再次取出更新之后的agvin队列任务发送wcs指令。。。");
					List<AgvInQueue> agvInQueueListForToWCS = agvInQueueService.list(Wrappers.<AgvInQueue>query().lambda()
							.eq(AgvInQueue::getOutPageNo,outPageNo)
							.orderByAsc(AgvInQueue::getId));

					agvInQueuetoWCS(agvInQueueListForToWCS);

				}else{
					log.info("AGV可用库位数小于单订单备货数部分备货。。。");
					log.info("从AGVin队列里取出部分此出库单任务后执行备货。。。出库单号为:"+outPageNo+"可用agv库位数是:"+agvSize);
					List<AgvInQueue> agvInQueueListForUpdate = agvInQueueService.list(Wrappers.<AgvInQueue>query().lambda()
							.eq(AgvInQueue::getOutPageNo,outPageNo)
							.orderByAsc(AgvInQueue::getId)
							.last("limit "+agvSize));
					log.info("取出部分agvin队列任务"+agvInQueueListForUpdate.size()+"条 循环更新备货出库信息。。。");
					updateAGVinQueue(agvInQueueListForUpdate);
					log.info("再次取出更新之后的agvin队列任务,不包括AGV信息为空的，发送wcs指令。。。");
					List<AgvInQueue> agvInQueueListForToWCS = agvInQueueService.list(Wrappers.<AgvInQueue>query().lambda()
							.eq(AgvInQueue::getOutPageNo,outPageNo)
							.isNotNull(AgvInQueue::getAgvLocationNo)
							.orderByAsc(AgvInQueue::getId));

					agvInQueuetoWCS(agvInQueueListForToWCS);

				}

			}else{
				log.warn("AGV备货区没有可用库位，单订单备货任务在队列中等待。。。出库单号是:"+outPageNo);
			}

		}else if(bhlx.equals(Constants.DBH)){
			log.info("开始处理多订单备货...");

			//校验备货库位数
			List<OutStorage> outStorageList = this.list(Wrappers.<OutStorage>query().lambda().in(OutStorage::getOutPageNo,
					chanxianOrB2COuts).orderByAsc(OutStorage::getCreateTime));
			//按时间排序的出库单wmsbillno
			List<String> chanxianWmsBillNosOuts = new ArrayList<>();

			for(OutStorage outStorage : outStorageList){
				chanxianWmsBillNosOuts.add(outStorage.getWmsBillNo());
			}

			//按时间排序的出库单pageno
			List<String> chanxianPageNosOuts = new ArrayList<>();

			for(OutStorage outStorage : outStorageList){
				chanxianPageNosOuts.add(outStorage.getOutPageNo());
			}

			List<OutStorageTp> outStorageTpList = outStorageTpService.list(Wrappers.<OutStorageTp>query().lambda()
					.in(OutStorageTp::getWmsBillNo, chanxianWmsBillNosOuts));
			int outTpSize = outStorageTpList.size();
			log.info("本次多订单备货所需库位数为"+outTpSize);

			List<SLocation> slocationList = sLocationService.list(Wrappers.<SLocation>query().lambda()
					.eq(SLocation::getAreaId, 10)
					.eq(SLocation::getIsUsed, "0")
					.eq(SLocation::getStatus, "1")
					.eq(SLocation::getLocationStatus, "1"));
			int agvSize = slocationList.size();
			log.info("当前AGV备货区可用库位数为"+agvSize);

			if(agvSize < outTpSize){
				log.error("当前AGV备货区可用库位数小于所需备货数，备货出现异常。。。");

				throw new RuntimeException("备货失败。。当前AGV备货区可用库位数小于所需备货数，备货出现异常。AGV可用库位数是:"+agvSize+
						"本次多订单备货所需库位数是"+outTpSize);

			}else{
				log.info("按照出库单时间升序和sku数量从小到大备货。");
				//库位数够用开始备货
				//按出库单日期从远到近开始出库
				for(OutStorage outStorage : outStorageList){
					List<OutStorageItem> outStorageItemListForBH = outStorageItemService.list(Wrappers.<OutStorageItem>query().lambda()
							.eq(OutStorageItem::getWmsBillNo, outStorage.getWmsBillNo()).orderByAsc(OutStorageItem::getSku)
							.orderByAsc(OutStorageItem::getBatchNo).orderByAsc(OutStorageItem::getAmount));
					//出库单行项目数量小的先出
					for(OutStorageItem outStorageItem : outStorageItemListForBH){
						List<OutStorageTp> outStorageTpListForBH = outStorageTpService.list(Wrappers.<OutStorageTp>query().lambda()
								.eq(OutStorageTp::getWmsBillNo, outStorageItem.getWmsBillNo())
								.eq(OutStorageTp::getOutStorageItemId, outStorageItem.getOutStorageItemId())
								.orderByAsc(OutStorageTp::getOutStorageTpId));
						//行项目托盘从大到小出库
						for(OutStorageTp outStorageTpForBH : outStorageTpListForBH){

							SLocation sLocationFromLiKu = sLocationService.getById(outStorageTpForBH.getLocation());
							AgvInQueue agvInQueue = new AgvInQueue();
							BeanUtils.copyProperties(sLocationFromLiKu, agvInQueue);
							agvInQueue.setMustNum(sLocationFromLiKu.getOutAmount());
							//AGV目标区一个库位
							SLocation agvSLocation = getAGVSlocation();
							//更新此库位为使用中
							agvSLocation.setIsUsed("2");
							agvSLocation.setUpdateTime(LocalDateTime.now());
							sLocationService.updateById(agvSLocation);
							agvInQueue.setAgvLocationNo(agvSLocation.getSLocationNo());
							agvInQueue.setOutPageNo(outStorage.getOutPageNo());
							agvInQueue.setOutStorageItemId(outStorageTpForBH.getOutStorageItemId());
							agvInQueue.setOutStorageTpId(outStorageTpForBH.getOutStorageTpId());
							agvInQueue.setOutLocation(outStorage.getLocationNo());
							agvInQueue.setBhlx(Constants.DBH);
							agvInQueue.setQueueStatus("0");
							agvInQueue.setCreateTime(null);
							agvInQueue.setUpdateTime(null);
							agvInQueueService.save(agvInQueue);
						}

					}

				}

				//所有出库单托盘任务已添加到agvin队列中 开始发送wcs指令
				//取出本次备货多订单所有任务按顺序 触发wcs出库指令
				List<AgvInQueue> agvInQueue = agvInQueueService.list(Wrappers.<AgvInQueue>query().lambda()
						.in(AgvInQueue::getOutPageNo, chanxianPageNosOuts)
						.orderByAsc(AgvInQueue::getId));
				log.info("找出"+agvInQueue.size()+"条多订单出库单，开始发送wcs指令。。。");
				agvInQueuetoWCS(agvInQueue);

			}


		}


	}

	private void updateAGVinQueue(List<AgvInQueue> agvInQueueListForUpdate) {
		for (AgvInQueue agvInQueueTask : agvInQueueListForUpdate) {
			log.info("先更新agvin队列任务中目标AGV库位和锁定目标AGV库位");
			//AGV目标区一个库位
			SLocation agvSLocation = getAGVSlocation();
			//更新此库位为使用中
			agvSLocation.setIsUsed("2");
			agvSLocation.setUpdateTime(LocalDateTime.now());
			sLocationService.updateById(agvSLocation);
			agvInQueueTask.setAgvLocationNo(agvSLocation.getSLocationNo());
			agvInQueueTask.setUpdateTime(LocalDateTime.now());
			agvInQueueService.updateById(agvInQueueTask);
			log.info("更新开始作业的agvin队列任务id为:" + agvInQueueTask.getId() + "锁定的agv目标库位是:" + agvSLocation.getSLocationNo());
		}
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void agvInQueuetoWCS(List<AgvInQueue> agvInQueue) {
		//保存多个wcs出库接口参数,最后用另外一个线程触发
		List<WCSInvOutDTO> wcsInvOutDTOList = new ArrayList<>();
		log.info("需要发送wcs指令的agvin队列数量为"+agvInQueue.size());
		for(AgvInQueue agvInQueue1 : agvInQueue){
			//获取任务中立库位置
			SLocation sLocationLK = sLocationService.getById(agvInQueue1.getSLocationNo());
			//usedSlocation中占用的库位发往wcs toAGV备货区
			WCSInvOutDTO wcsInvOutDTO = new WCSInvOutDTO();
			String taskId = "wmstrx" + LocalDateTime.now()
					.format(DateTimeFormatter.ofPattern(DatePattern.PURE_DATETIME_MS_PATTERN));
			wcsInvOutDTO.setTaskId(taskId);
			wcsInvOutDTO.setInvOutType("13");
			wcsInvOutDTO.setOutLoc(sLocationLK.getSLocationNo());
			wcsInvOutDTO.setStockNo(sLocationLK.getTrayNo());
			wcsInvOutDTO.setLocDesti(agvInQueue1.getAgvLocationNo());
			wcsInvOutDTO.setMemoInfo1("wms调用wcs备货出库接口,toAGV备货区");
			wcsInvOutDTO.setMemoInfo2(sLocationLK.getStockAreaNo());

			wcsInvOutDTOList.add(wcsInvOutDTO);

			WcsWmsTrx wcsWmsTrx = new WcsWmsTrx();
			wcsWmsTrx.setWmsTrxId(taskId);
			wcsWmsTrx.setTrxType("13");
			wcsWmsTrx.setFromLocation(sLocationLK.getSLocationNo());
			wcsWmsTrx.setToLocation(agvInQueue1.getAgvLocationNo());
			wcsWmsTrx.setTrayNo(sLocationLK.getTrayNo());
			wcsWmsTrxMapper.insert(wcsWmsTrx);

			//更新队列状态为正在作业
			agvInQueue1.setQueueStatus("2");
			agvInQueue1.setUpdateTime(LocalDateTime.now());
			agvInQueueService.updateById(agvInQueue1);
		}

		log.info("多个出库单已更新队列状态,启动新线程调用wcs出库接口");

		OutCallWcsThread outCallWcsThread = new OutCallWcsThread(wcsInvOutDTOList,wcsWmsTrxService);
		outCallWcsThread.start();
	}

	@Override
	public List<BHOutForPDAVO> bhOutForPDAVO(String outPageNo) {

		List<OutStorage> outStorages = null;

		if(StringUtils.isBlank(outPageNo)){
			log.info("outPageNo是空，查询所有备货中或备货完成的出库单");
			outStorages = this.list(Wrappers.<OutStorage>query().lambda()
					.or().eq(OutStorage::getStatus,"6")
					.or().eq(OutStorage::getStatus,"7")
					.orderByAsc(OutStorage::getCreateTime));

		}else{
			log.info("outPageNo不是空，查询对应的备货中或备货完成的出库单");
			outStorages = this.list(Wrappers.<OutStorage>query().lambda()
					.like(OutStorage::getOutPageNo,outPageNo)
					.and(tmp->tmp.eq(OutStorage::getStatus,"6")
					.or().eq(OutStorage::getStatus,"7"))
					.orderByAsc(OutStorage::getCreateTime));
		}

		if(null == outStorages || outStorages.size() == 0){
			log.info("没有备货中或备货完成的出库单。。。");
			return  null;
		}
		List<BHOutForPDAVO> bhOutForPDAVOS = new ArrayList<>();

		for(OutStorage outStorage : outStorages){
			BHOutForPDAVO bhOutForPDAVO = new BHOutForPDAVO();
			bhOutForPDAVO.setOutPageNo(outStorage.getOutPageNo());
			bhOutForPDAVO.setStatus(outStorage.getStatus());
			List<BHOutDetailForPDAVO> bhOutDetailForPDAVOS = new ArrayList<>();
			List<OutStorageItem> outStorageItems = outStorageItemService.list(Wrappers.<OutStorageItem>query().lambda()
					.eq(OutStorageItem::getWmsBillNo,outStorage.getWmsBillNo())
					.orderByAsc(OutStorageItem::getAmount));
			for(OutStorageItem outStorageItem : outStorageItems){
				BHOutDetailForPDAVO bhOutDetailForPDAVO = new BHOutDetailForPDAVO();
				bhOutDetailForPDAVO.setSku(outStorageItem.getSku());
				List<OutStorageTp> outStorageTps = outStorageTpService.list(Wrappers.<OutStorageTp>query().lambda()
						.eq(OutStorageTp::getWmsBillNo,outStorageItem.getWmsBillNo())
						.eq(OutStorageTp::getOutStorageItemId,outStorageItem.getOutStorageItemId()));
				bhOutDetailForPDAVO.setTpNum(outStorageTps.size());
				bhOutDetailForPDAVOS.add(bhOutDetailForPDAVO);
			}
			bhOutForPDAVO.setSkuTps(bhOutDetailForPDAVOS);
			bhOutForPDAVOS.add(bhOutForPDAVO);
		}

		return bhOutForPDAVOS;
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void submitOutDetailAndBack(OutDetailAndBackForPDADTO outDetailAndBackForPDADTO) {

		OutStorageTp outStorageTp = outStorageTpService.getOne(Wrappers.<OutStorageTp>query().lambda()
				.eq(OutStorageTp::getUniqueCode,outDetailAndBackForPDADTO.getTpNo()).eq(OutStorageTp::getStatus,"0"));

		outStorageTp.setRealAmount(0);
		outStorageTp.setOperator(SecurityUtils.getUser().getUsername());
		outStorageTp.setStatus("3");
		outStorageTp.setUpdateTime(LocalDateTime.now());
		outStorageTpService.updateById(outStorageTp);

		OutStorageItem outStorageItem =
				outStorageItemService
						.getOne(Wrappers.<OutStorageItem>query().lambda().eq(OutStorageItem::getOutStorageItemId,
								outStorageTp.getOutStorageItemId()));

		OutStorage outStorage =
				this.getOne(Wrappers.<OutStorage>query().lambda().eq(OutStorage::getWmsBillNo,
						outStorageItem.getWmsBillNo()));

		List<OutStorageTp> outStorageTpList = outStorageTpService.list(Wrappers.<OutStorageTp>query().lambda()
				.eq(OutStorageTp::getWmsBillNo,outStorageTp.getWmsBillNo()));

		List<B2bTaskRecord> b2bTaskRecords = b2bTaskRecordService.list(Wrappers.<B2bTaskRecord>query().lambda()
				.eq(B2bTaskRecord::getWmsBillNo,outStorageTp.getWmsBillNo()));

		if(outStorageTpList.size()-1 == b2bTaskRecords.size()){

			//如果是出库单中最后一个托盘，就清空临时出库托盘信息 并更新出库单状态为已完成
			b2bTaskRecordService.remove(Wrappers.<B2bTaskRecord>query().lambda()
					.eq(B2bTaskRecord::getWmsBillNo,outStorageTp.getWmsBillNo()));
			outStorage.setStatus("3");
			outStorage.setPackageStatus("3");
			this.updateById(outStorage);

			log.info("出库托盘提交处理完毕，继续处理托盘返库逻辑~");
			this.tpBackForPDA(outDetailAndBackForPDADTO);

			//回调ERP：下架回调接口
			log.info("调用ERP下架回调开始...这是最后一个托盘回库 回传ERP orderstatus1和行项目");
			ERPOutStorageDTO erpOutStorageDTO = new ERPOutStorageDTO();
			DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

			List<OutStorageItem> outStorageItemList =
					outStorageItemService.list(Wrappers.<OutStorageItem>query().lambda().eq(OutStorageItem::getOutStorageItemId,
							outStorageTp.getOutStorageItemId()));

			List<ERPOutStorageItemDTO> erpOutStorageItemDTOS = new ArrayList<>();
			for(OutStorageItem outStorageItemForErp : outStorageItemList){
				ERPOutStorageItemDTO erpOutStorageItemDTO = new ERPOutStorageItemDTO();

				List<OutStorageTp> outStorageTpListForItem =
						outStorageTpService.list(Wrappers.<OutStorageTp>query().lambda()
								.eq(OutStorageTp::getOutStorageTpId,outStorageTp.getOutStorageTpId()));

				List<ERPOutStorageTpDTO> erpOutStorageTpDTOList = new ArrayList<>();

				for(OutStorageTp outStorageTpForERP : outStorageTpListForItem){

					ERPOutStorageTpDTO erpOutStorageTpDTO = new ERPOutStorageTpDTO();
					BeanUtils.copyProperties(outStorageTpForERP, erpOutStorageTpDTO);
					erpOutStorageTpDTO.setAmount(outStorageTpForERP.getRealAmount());
					erpOutStorageTpDTOList.add(erpOutStorageTpDTO);

				}
				erpOutStorageItemDTO.setErpOutStorageTpDTOList(erpOutStorageTpDTOList);

				BeanUtils.copyProperties(outStorageItemForErp, erpOutStorageItemDTO);

				erpOutStorageItemDTOS.add(erpOutStorageItemDTO);
			}
			erpOutStorageDTO.setErpOutStorageItemDTOList(erpOutStorageItemDTOS);
			BeanUtils.copyProperties(outStorage, erpOutStorageDTO);

			String  outDateStr = outStorage.getOutDate().format(formatter);
			erpOutStorageDTO.setOutDate(outDateStr);
			erpOutStorageDTO.setOrderStatus("1");
			try{
				erpCallBackService.callBackOut(erpOutStorageDTO);
				log.info("调用ERP下架回调完成。");

			}catch (Exception e){
				log.error("调用ERP下架回调出现异常！"+e.getMessage());
				e.printStackTrace();
			}

		}else{
			B2bTaskRecord b2bTaskRecord = new B2bTaskRecord();
			b2bTaskRecord.setWmsBillNo(outStorageTp.getWmsBillNo());
			b2bTaskRecord.setOutTpId(outStorageTp.getOutStorageTpId());
			b2bTaskRecord.setTpNo(outDetailAndBackForPDADTO.getTpNo());
			b2bTaskRecord.setSku(outStorageTp.getSku());
			Sku sku = skuService.getById(outStorageTp.getSku());
			b2bTaskRecord.setSkuName(sku.getGdname());
			b2bTaskRecord.setRealAmount(0);
			b2bTaskRecord.setOperator(SecurityUtils.getUser().getUsername());

			b2bTaskRecordService.save(b2bTaskRecord);
			//出库中
			outStorage.setStatus("2");
			this.updateById(outStorage);

			log.info("出库托盘提交处理完毕，继续处理托盘返库逻辑~");
			this.tpBackForPDA(outDetailAndBackForPDADTO);

			//回调ERP：下架回调接口
			log.info("调用ERP下架回调开始...这不是最后一个托盘回库 回传ERP orderstatus 0和行项目");
			ERPOutStorageDTO erpOutStorageDTO = new ERPOutStorageDTO();
			DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

			List<OutStorageItem> outStorageItemList =
					outStorageItemService.list(Wrappers.<OutStorageItem>query().lambda().eq(OutStorageItem::getOutStorageItemId,
							outStorageTp.getOutStorageItemId()));

			List<ERPOutStorageItemDTO> erpOutStorageItemDTOS = new ArrayList<>();
			for(OutStorageItem outStorageItemForErp : outStorageItemList){
				ERPOutStorageItemDTO erpOutStorageItemDTO = new ERPOutStorageItemDTO();

				List<OutStorageTp> outStorageTpListForItem =
						outStorageTpService.list(Wrappers.<OutStorageTp>query().lambda()
								.eq(OutStorageTp::getOutStorageTpId,outStorageTp.getOutStorageTpId()));

				List<ERPOutStorageTpDTO> erpOutStorageTpDTOList = new ArrayList<>();

				for(OutStorageTp outStorageTpForERP : outStorageTpListForItem){

					ERPOutStorageTpDTO erpOutStorageTpDTO = new ERPOutStorageTpDTO();
					BeanUtils.copyProperties(outStorageTpForERP, erpOutStorageTpDTO);
					erpOutStorageTpDTO.setAmount(outStorageTpForERP.getRealAmount());
					erpOutStorageTpDTOList.add(erpOutStorageTpDTO);

				}
				erpOutStorageItemDTO.setErpOutStorageTpDTOList(erpOutStorageTpDTOList);

				BeanUtils.copyProperties(outStorageItemForErp, erpOutStorageItemDTO);

				erpOutStorageItemDTOS.add(erpOutStorageItemDTO);
			}
			erpOutStorageDTO.setErpOutStorageItemDTOList(erpOutStorageItemDTOS);
			BeanUtils.copyProperties(outStorage, erpOutStorageDTO);

			String  outDateStr = outStorage.getOutDate().format(formatter);
			erpOutStorageDTO.setOutDate(outDateStr);
			erpOutStorageDTO.setOrderStatus("0");
			try{
				erpCallBackService.callBackOut(erpOutStorageDTO);
				log.info("调用ERP下架回调完成。");

			}catch (Exception e){
				log.error("调用ERP下架回调出现异常！"+e.getMessage());
				e.printStackTrace();
			}
		}

	}

	@Override
//	@Transactional(rollbackFor = Exception.class)
	public void tpBackForPDA(OutDetailAndBackForPDADTO outDetailAndBackForPDADTO) {
		synchronized (InStorageServiceImpl.class){
			log.info("开始处理PDA托盘回库逻辑~获取并锁定入库事务锁。。。");

		TraySku traySku = traySkuService.getById(outDetailAndBackForPDADTO.getTpNo());
		traySku.setStockNum(traySku.getStockNum());
		traySku.setUpdateTime(LocalDateTime.now());
		traySkuService.updateById(traySku);

		//如果是需要返库的托盘 先释放占用的库位和库区 再入库
		if(traySku.getStockNum() > traySku.getMustNum()){
			log.info("这是需要返库的托盘 先释放返库库区库位 traySku 托盘编号是："+outDetailAndBackForPDADTO.getTpNo());

			//找出返库立库库位位置
			SLocation sLocationFrom =
					sLocationService.getOne(Wrappers.<SLocation>query().lambda().eq(SLocation::getSLocationNo,
							traySku.getSLocationNo()));
			//释放库位
			sLocationFrom.setTrayNo(null);
			sLocationFrom.setBatchNo("");
			sLocationFrom.setBatchCi("");
			sLocationFrom.setSku(null);
			sLocationFrom.setHuozId(null);
			sLocationFrom.setRealHuoz(null);
			sLocationFrom.setStockNum(0);
			sLocationFrom.setOutAmount(0);
			sLocationFrom.setIsUsed("0");
			sLocationFrom.setLocationStatus("1");
			sLocationFrom.setInPageNo("");
			sLocationFrom.setInStorageItemId(0);
			sLocationFrom.setUpdateTime(LocalDateTime.now());
			//更新库位信息
			sLocationService.updateById(sLocationFrom);
			log.info("已释放"+sLocationFrom.getSLocationNo()+"库位");

			//检查库区情况是否释放库区
			StockArea stockArea = stockAreaService.getById(sLocationFrom.getStockAreaNo());

			log.info("检查"+stockArea.getStockAreaNo()+"库区是否可以释放");
			log.info("检查"+stockArea.getStockAreaNo()+"库区是否有location_status=4的情况");
			List<SLocation> sLocationList =
					sLocationService.list(Wrappers.<SLocation>query().lambda().eq(SLocation::getStockAreaNo,
									stockArea.getStockAreaNo())
							.eq(SLocation::getIsUsed, "1")
							.eq(SLocation::getLocationStatus,"4")
							.eq(SLocation::getStatus, "1"));
			log.info("检查结果:有"+sLocationList.size()+"个");

			log.info("检查"+stockArea.getStockAreaNo()+"库区是否有is_used=2的情况,正在使用中的");
			List<SLocation> sLocationListUsing =
					sLocationService.list(Wrappers.<SLocation>query().lambda().eq(SLocation::getStockAreaNo,
									stockArea.getStockAreaNo())
							.eq(SLocation::getIsUsed, "2")
							.eq(SLocation::getStatus, "1"));

			log.info("检查结果:有"+sLocationListUsing.size()+"个");

			sLocationList.addAll(sLocationListUsing);

			if(sLocationList.size() == 0){

				stockArea.setInBillNumber("");
				stockArea.setBatchNo("");
				stockArea.setSku(null);
				stockArea.setStatus("0");
				stockArea.setLockStatus("0");
				stockAreaService.updateById(stockArea);
				log.info(stockArea.getStockAreaNo()+"库区没有找到正在使用有托盘货物并激活的库位，已经释放库区");
			}else{
				log.info(stockArea.getStockAreaNo()+"库区找到正在使用有托盘货物并激活的库位，不可以释放");
			}

		}

		log.info("处理库区查找是否使用ERP盘点后的inbillnumber");
		ERPCheckFeedback erpCheckFeedback = erpCheckFeedbackService.getOne(Wrappers.<ERPCheckFeedback>query().lambda()
				.eq(ERPCheckFeedback::getItemId, traySku.getBatchCi())
				.eq(ERPCheckFeedback::getUniqueCode, traySku.getTrayNo())
				.orderByDesc(ERPCheckFeedback::getCreateTime).last("limit 1"));

		InStorageItem inStorageItem;
		InStorage instorage;

		if(null != erpCheckFeedback){
			log.info("查出在ERP盘点反馈中有此托盘信息，创建虚拟入库单保存inbillnumber");
			//虚拟入库单和行项目
			InStorage inStorageNew = new InStorage();
			inStorageNew.setInBillNumber(erpCheckFeedback.getInBillNumber());
			instorage = inStorageNew;

			InStorageItem inStorageItemNew = new InStorageItem();
			inStorageItemNew.setSku(erpCheckFeedback.getConfirmSku());
			inStorageItemNew.setBatchNo(erpCheckFeedback.getConfirmBatchNo());
			inStorageItem = inStorageItemNew;

		}else{
			//重新入库
			//获取入库单信息
			log.info("没有查出在ERP盘点反馈中有此托盘信息，查询原始入库单信息 获取库区");
			inStorageItem = inStorageItemService.getById(traySku.getInStorageItemId());

			instorage = inStorageService.getById(traySku.getInPageNo());
		}

		StockArea stockArea = null;
		try {
			stockArea = inStorageService.getStockArea(inStorageItem, instorage, "15");
		} catch (Exception e) {
			log.error("获取库区出现异常。。。没找到库区");
			e.printStackTrace();
			throw new RuntimeException("回库异常!!!");
		}

		if(null == stockArea){
			log.error("获取库区出现异常。。。没找到库区");
			throw new RuntimeException("回库异常!!!");
		}
		//获取启用的立库区未使用的排序级别最高的库位编号
		SLocation sLocation =
				sLocationService.getOne(Wrappers.<SLocation>query().lambda().eq(SLocation::getStatus, 1)
						.eq(SLocation::getAreaId, 1).eq(SLocation::getIsUsed, 0)
						.eq(SLocation::getLocationStatus,"1")
						.eq(SLocation::getStockAreaNo,stockArea.getStockAreaNo())
						.orderByAsc(SLocation::getSOrder).last("limit 1"));

		if (sLocation == null) {

			throw new RuntimeException("回库异常!!!");

		} else {

			String sNo = sLocation.getSLocationNo();
			sLocation.setIsUsed("2");
			sLocation.setUpdateTime(LocalDateTime.now());
			sLocationService.updateById(sLocation);

			//更新库区状态 先检查是否符合预占用状态
			boolean yzyStatus = stockAreaService.checkStockAreaYuZhanYong(stockArea.getStockAreaNo());

			if(yzyStatus){

				//更新库区为预占用状态
				StockArea stockAreaForCheck = stockAreaService.getById(sLocation.getStockAreaNo());
				stockAreaForCheck.setSku(stockAreaForCheck.getSku());
				stockAreaForCheck.setLockStatus("2");
				stockAreaService.updateById(stockAreaForCheck);
				log.info("更新库区为预占用状态,库区:"+sLocation.getStockAreaNo());

			}else{
				log.info("库区不符合预占用状态,按原来逻辑更新库区信息:"+sLocation.getStockAreaNo());
				//查找此库位所属库区是否有可使用的库位 判断是否锁定库区
				log.info("回库检查库区状态,查找此库位所属库区是否有可使用的库位,库区:"+sLocation.getStockAreaNo());
				SLocation sLocationForCheck =
						sLocationService.getOne(Wrappers.<SLocation>query().lambda().eq(SLocation::getStatus, 1)
								.eq(SLocation::getAreaId, 1).eq(SLocation::getIsUsed, 0)
								.eq(SLocation::getStockAreaNo,sLocation.getStockAreaNo())
								.eq(SLocation::getLocationStatus,"1")
								.orderByAsc(SLocation::getSOrder).last("limit 1"));
				if(null == sLocationForCheck){
					//如果没有可使用的库位，更新库区为锁定状态
					StockArea stockAreaForCheck = stockAreaService.getById(sLocation.getStockAreaNo());
					stockAreaForCheck.setSku(stockAreaForCheck.getSku());
					stockAreaForCheck.setStatus("2");
					stockAreaForCheck.setLockStatus("1");
					stockAreaService.updateById(stockAreaForCheck);
					log.info("没有可使用的库位，更新库区为锁定状态,库区:"+sLocation.getStockAreaNo());
				}else{

					//如果有可使用的库位，更新库区为未锁定状态
					StockArea stockAreaForCheck = stockAreaService.getById(sLocation.getStockAreaNo());
					stockAreaForCheck.setSku(stockAreaForCheck.getSku());
					stockAreaForCheck.setStatus("1");
					stockAreaForCheck.setLockStatus("0");
					stockAreaService.updateById(stockAreaForCheck);
					log.info("有可使用的库位，更新库区为未锁定状态,库区:"+sLocation.getStockAreaNo());

				}
			}

			//调用wcs做回库
			WCSInvInDTO wcsInvInDTO = new WCSInvInDTO();
			String taskId = "wmstrx" + LocalDateTime.now()
					.format(DateTimeFormatter.ofPattern(DatePattern.PURE_DATETIME_MS_PATTERN));
			wcsInvInDTO.setTaskId(taskId);
			wcsInvInDTO.setTaskSource("15");
			wcsInvInDTO.setLocatorFrom(outDetailAndBackForPDADTO.getFromLocation());
			wcsInvInDTO.setInloc(sNo);
			wcsInvInDTO.setStockNo(outDetailAndBackForPDADTO.getTpNo());
			wcsInvInDTO.setMemoInfo1("wms调用wcs做回库");
			wcsInvInDTO.setMemoInfo2(stockArea.getStockAreaNo());

			if(!wcsWmsTrxService.handleWCSInvIn(wcsInvInDTO)){
				throw new RuntimeException("调用WCS入库接口异常!!!");
			}

			WcsWmsTrx wcsWmsTrx = new WcsWmsTrx();
			wcsWmsTrx.setWmsTrxId(taskId);
			wcsWmsTrx.setTrxType("15");
			wcsWmsTrx.setTrayNo(outDetailAndBackForPDADTO.getTpNo());
			wcsWmsTrx.setFromLocation(outDetailAndBackForPDADTO.getFromLocation());
			wcsWmsTrx.setToLocation(sNo);

			wcsWmsTrxService.save(wcsWmsTrx);
		}
		    log.info("PDA回库逻辑处理完成，正在释放入库事务锁。。。");
		}
	}

	private SLocation getAGVSlocation() {

		SLocation agvSLocation =
				sLocationService.getOne(Wrappers.<SLocation>query().lambda().eq(SLocation::getAreaId,10)
						.eq(SLocation::getIsUsed,"0")
						.eq(SLocation::getLocationStatus,"1")
						.eq(SLocation::getStatus,"1")
						.orderByAsc(SLocation::getSOrder).last("limit 1"));
		if(null == agvSLocation){
			log.error("异常~~ 没找到AGV区可用库位。。。");
			throw new RuntimeException("获取AGV可用库位失败，没找到AGV可用库位，抛出异常！~~回滚之前的操作。。。");
		}

		return agvSLocation;
	}

	private void handleDSOut(CreatePackageReturnDTO createPackageReturnDTO, List<String> dianshangOuts) {

		boolean canPackage;

		boolean needBH;

		//需要出库的货品和数量总和
		Map<String,Integer> skuAmount = new HashMap<>();

		//需要补货出库的货品和数量总和
		Map<String,Integer> skuAmountBH = new HashMap<>();

		//电商区的出货库位
		Map<String,List<SLocation>> usedDSSlocationForSku = new HashMap<>();

		//立库区的出货库位
		Map<String,List<SLocation>> usedLKSlocationForSku = new HashMap<>();

		//先计算此波次电商订单所需货品总库存
		sumStockAmount(dianshangOuts, skuAmount);

		//计算电商区库存够不够
		needBH = stockAmountFromDS(skuAmount, skuAmountBH, usedDSSlocationForSku);

		if(needBH){
            //如果需要补货就计算剩余出库数在立库区库存够不够
			canPackage = stockAmountFromLK(skuAmountBH,usedLKSlocationForSku);

			if(!canPackage){

				//释放电商区的占用库存
				for(String sku : usedDSSlocationForSku.keySet()){
					for(SLocation sLocation : usedDSSlocationForSku.get(sku)){
						sLocation.setIsUsed("1");
						sLocation.setUpdateTime(LocalDateTime.now());
						sLocationService.updateById(sLocation);
					}
				}

				//释放电商区的占用库存
				for(String sku : usedLKSlocationForSku.keySet()){
					for(SLocation sLocation : usedLKSlocationForSku.get(sku)){
						sLocation.setIsUsed("1");
						sLocation.setUpdateTime(LocalDateTime.now());
						sLocationService.updateById(sLocation);
					}
				}

				createPackageReturnDTO.setSuccess(false);
				createPackageReturnDTO.setMessage("电商订单库存不足，无法下发波次");
			}else{

				//开始提总补货 电商区和立库区一起提总补货
				//创建波次单号 补货状态
				String packageNo = createPackageForOut(dianshangOuts,"1");

				//组合电商区货位信息和立库区货位信息,把立库区的库位信息组合到电商库位信息中
				combineDSandLK(usedDSSlocationForSku, usedLKSlocationForSku);

				//创建子波次 使用电商区的库位信息出库
				createSubPackageAndInfoForDSOut(packageNo,dianshangOuts,usedDSSlocationForSku);

				//保存组合区补货信息
				saveBhInfo(usedDSSlocationForSku, packageNo);

				//把立库区补货库位信息copy到库位临时表中
				//查找L区补货区的库位信息
				SLocation sLocationTO =
						sLocationService.getOne(Wrappers.<SLocation>query().lambda().eq(SLocation::getAreaId,"10")
								.eq(SLocation::getIsUsed,"0")
								.eq(SLocation::getLocationStatus,"1").eq(SLocation::getStatus,"1")
								.orderByAsc(SLocation::getSOrder).last("limit 1"));

				for(String sku : usedDSSlocationForSku.keySet()){

					for(SLocation sLocation : usedDSSlocationForSku.get(sku)){

						TraySku traySku = new TraySku();
						BeanUtils.copyProperties(sLocation,traySku);
						traySku.setCreateTime(null);
						traySku.setUpdateTime(null);
						traySkuService.save(traySku);

						//调用wcs把立库区补货商品发往电商区 L区
						WCSInvOutDTO wcsInvOutDTO = new WCSInvOutDTO();
						String taskId = "wmstrx" + LocalDateTime.now()
								.format(DateTimeFormatter.ofPattern(DatePattern.PURE_DATETIME_MS_PATTERN));
						wcsInvOutDTO.setTaskId(taskId);
						wcsInvOutDTO.setInvOutType("12");
						wcsInvOutDTO.setOutLoc(sLocation.getSLocationNo());
						wcsInvOutDTO.setStockNo(sLocation.getTrayNo());
						wcsInvOutDTO.setLocDesti(sLocationTO.getSLocationNo());
						wcsInvOutDTO.setMemoInfo1("wms调用wcs出库接口,把立库区补货商品发往电商区 L区");

						if(!wcsWmsTrxService.handleWCSInvOut(wcsInvOutDTO)){
							throw new RuntimeException("调用WCS出库接口异常!!!");
						}

						WcsWmsTrx wcsWmsTrx = new WcsWmsTrx();
						wcsWmsTrx.setWmsTrxId(taskId);
						wcsWmsTrx.setTrxType("12");
						wcsWmsTrx.setFromLocation(sLocation.getSLocationNo());
						wcsWmsTrx.setToLocation(sLocationTO.getSLocationNo());
						wcsWmsTrx.setTrayNo(sLocation.getTrayNo());
						wcsWmsTrxMapper.insert(wcsWmsTrx);

					}

				}

				//从电商区和立库区分配电商订单的托盘信息
				//fenpeiDSTPInfoFromDSLK(dianshangOuts, usedDSSlocationForSku,usedLKSlocationForSku);

				createPackageReturnDTO.setSuccess(true);
				createPackageReturnDTO.setMessage("电商波次创建成功，由于电商区货品不足，开始从立库区补货...");

			}

		}else{

			//电商区货品数量充足 可以创建波次和出库

			//创建波次单号 原来是待出库状态 现在改为补货提总状态
			String packageNo = createPackageForOut(dianshangOuts,"1");

			//创建子波次 使用电商区的库位信息出库
			createSubPackageAndInfoForDSOut(packageNo,dianshangOuts,usedDSSlocationForSku);

//			OutStorage outStorage = this.getOne(Wrappers.<OutStorage>query().lambda().eq(OutStorage::getPackageStatus,
			//					"1").last("limit 1"));

			//通知wms运送货物,做电商提总补货
			callWCSForDSTZ();

			//从电商区分配电商订单的托盘信息
			//fenpeiDSTPInfo(dianshangOuts, usedDSSlocationForSku);

			//更新出库单状态为待出库
			for(String out : dianshangOuts){
				OutStorage outStorage = this.getById(out);
				outStorage.setStatus("1");
				this.updateById(outStorage);
			}

			createPackageReturnDTO.setSuccess(true);
			createPackageReturnDTO.setMessage("电商波次和子波次创建成功，正在提总补货");

		}

	}

	private void callWCSForDSTZ() {
		SubPackage subPackage = subPackageService.getOne(Wrappers.<SubPackage>query().lambda().eq(SubPackage::getStatus,
			"2").last("limit 1"));

		List<SubPackageInfo> subPackageInfos = subPackageInfoService.list(Wrappers.<SubPackageInfo>query().lambda()
				.eq(SubPackageInfo::getSubPackageNo,subPackage.getSubPackageNo()));

		for(SubPackageInfo subPackageInfo : subPackageInfos){

			SLocation sLocation = sLocationService.getById(subPackageInfo.getFromLocation());
			TraySku traySku = new TraySku();
			BeanUtils.copyProperties(sLocation,traySku);
			traySku.setCreateTime(null);
			traySku.setUpdateTime(null);
			traySkuService.save(traySku);

			//调用wcs把补货商品发往电商区 L区
			WCSInvOutDTO wcsInvOutDTO = new WCSInvOutDTO();
			String taskId = "wmstrx" + LocalDateTime.now()
					.format(DateTimeFormatter.ofPattern(DatePattern.PURE_DATETIME_MS_PATTERN));
			wcsInvOutDTO.setTaskId(taskId);
			wcsInvOutDTO.setInvOutType("12");
			wcsInvOutDTO.setOutLoc(sLocation.getSLocationNo());
			wcsInvOutDTO.setStockNo(sLocation.getTrayNo());
			wcsInvOutDTO.setLocDesti(subPackageInfo.getLLocation());
			wcsInvOutDTO.setMemoInfo1("wms调用wcs出库接口,把补货商品发往电商区 L区"+subPackageInfo.getLLocation());

			if(!wcsWmsTrxService.handleWCSInvOut(wcsInvOutDTO)){
				throw new RuntimeException("调用WCS出库接口异常!!!");
			}

			WcsWmsTrx wcsWmsTrx = new WcsWmsTrx();
			wcsWmsTrx.setWmsTrxId(taskId);
			wcsWmsTrx.setTrxType("12");
			wcsWmsTrx.setFromLocation(sLocation.getSLocationNo());
			wcsWmsTrx.setToLocation(subPackageInfo.getLLocation());
			wcsWmsTrx.setTrayNo(sLocation.getTrayNo());
			wcsWmsTrxMapper.insert(wcsWmsTrx);
		}
	}

	private void combineDSandLK(Map<String, List<SLocation>> usedDSSlocationForSku,
								Map<String, List<SLocation>> usedLKSlocationForSku) {
		for(String skuDS: usedDSSlocationForSku.keySet()){

			List<SLocation> sLocationList = usedDSSlocationForSku.get(skuDS);

			if(usedLKSlocationForSku.get(skuDS) != null){

				sLocationList.addAll(usedLKSlocationForSku.get(skuDS));
				usedLKSlocationForSku.remove(skuDS);
			}

		}
		usedDSSlocationForSku.putAll(usedLKSlocationForSku);
	}

	private void saveBhInfo(Map<String, List<SLocation>> usedLKSlocationForSku, String packageNo) {
		for(String sku : usedLKSlocationForSku.keySet()){

			List<SLocation> locations = usedLKSlocationForSku.get(sku);
			String skuName = skuService.getById(sku).getGdname();

			for(SLocation location : locations){

				BhTMP bhTMP = new BhTMP();
				bhTMP.setPackageNo(packageNo);
				bhTMP.setTpNo(location.getTrayNo());
				bhTMP.setSku(sku);
				bhTMP.setSkuName(skuName);
				bhTMPService.save(bhTMP);

			}

		}
	}

	private void fenpeiDSTPInfoFromDSLK(List<String> dianshangOuts, Map<String, List<SLocation>> usedDSSlocationForSku, Map<String, List<SLocation>> usedLKSlocationForSku) {

		for(String DSOut : dianshangOuts){

			OutStorage outStorage = this.getById(DSOut);

			//获取出库单的行项目
			List<OutStorageItem> outStorageItemList = outStorageItemService.list(
					Wrappers.<OutStorageItem>query().lambda().eq(OutStorageItem::getWmsBillNo, outStorage.getWmsBillNo()));

			for(OutStorageItem outStorageItem : outStorageItemList) {

				int outAmount = outStorageItem.getAmount();
				String sku = outStorageItem.getSku();
				int outAmountLeft = outAmount;

				//获取此sku相关的库位信息
				List<SLocation> sLocationList =  usedDSSlocationForSku.get(sku);

				//获取此sku相关的库位立库信息
				List<SLocation> sLocationLKList =  usedLKSlocationForSku.get(sku);


				OutStorageTp outStorageTp = new OutStorageTp();
				outStorageTp.setWmsBillNo(outStorageItem.getWmsBillNo());
				outStorageTp.setOutStorageItemId(outStorageItem.getOutStorageItemId());
				outStorageTp.setSku(sku);
				outStorageTp.setOperator(SecurityUtils.getUser().getUsername());

				//如果电商区没有此商品就从立库里分配
				if(sLocationList == null){

					for(SLocation sLocation : sLocationLKList){

						//原始库存数
						int ysAmount = outStorageItem.getAmount();

						if(outAmount < sLocation.getStockNum()){
							//减去占用库存数
							sLocation.setStockNum(outStorageItem.getAmount() - outAmount);
							outStorageTp.setUniqueCode(sLocation.getTrayNo());
							outStorageTp.setItemId(sLocation.getBatchCi());
							outStorageTp.setSAmount(ysAmount);
							outStorageTp.setRealAmount(outAmount);
							outStorageTp.setLocation(sLocation.getSLocationNo());
							outStorageTpService.save(outStorageTp);
							break;

						}else if(outAmountLeft == sLocation.getStockNum()){

							//减去占用库存数
							sLocation.setStockNum(outStorageItem.getAmount() - outAmountLeft);
							outStorageTp.setUniqueCode(sLocation.getTrayNo());
							outStorageTp.setItemId(sLocation.getBatchCi());
							outStorageTp.setSAmount(ysAmount);
							outStorageTp.setRealAmount(outAmountLeft);
							outStorageTp.setLocation(sLocation.getSLocationNo());
							outStorageTpService.save(outStorageTp);

							//移除当前库位信息
							sLocationList.remove(sLocation);
							break;

						}else{

							//减去占用库存数
							sLocation.setStockNum(outStorageItem.getAmount() - outAmountLeft);

							outStorageTp.setUniqueCode(sLocation.getTrayNo());
							outStorageTp.setItemId(sLocation.getBatchCi());
							outStorageTp.setSAmount(ysAmount);
							outStorageTp.setRealAmount(outStorageItem.getAmount() - outAmountLeft);
							outStorageTp.setLocation(sLocation.getSLocationNo());
							outStorageTpService.save(outStorageTp);

							outAmountLeft = outAmountLeft - sLocation.getStockNum();

							//移除当前库位信息
							sLocationList.remove(sLocation);

						}

					}

				}

				for(SLocation sLocation : sLocationList){

					//原始发货数
					int ysAmount = outStorageItem.getAmount();

					if(outAmount < sLocation.getStockNum()){
						outAmountLeft = 0;
						//减去占用库存数
						sLocation.setStockNum(outStorageItem.getAmount() - outAmount);
						outStorageTp.setUniqueCode(sLocation.getTrayNo());
						outStorageTp.setItemId(sLocation.getBatchCi());
						outStorageTp.setSAmount(ysAmount);
						outStorageTp.setLocation(sLocation.getSLocationNo());
						outStorageTpService.save(outStorageTp);
						break;

					}else if(outAmountLeft == sLocation.getStockNum()){

						//减去占用库存数
						sLocation.setStockNum(outStorageItem.getAmount() - outAmountLeft);
						outStorageTp.setUniqueCode(sLocation.getTrayNo());
						outStorageTp.setItemId(sLocation.getBatchCi());
						outStorageTp.setSAmount(ysAmount);
						outStorageTp.setLocation(sLocation.getSLocationNo());
						outStorageTpService.save(outStorageTp);

						//移除当前库位信息
						sLocationList.remove(sLocation);
						break;

					}else{

						//减去占用库存数
						outAmountLeft = outAmountLeft - sLocation.getStockNum();
						outStorageTp.setUniqueCode(sLocation.getTrayNo());
						outStorageTp.setItemId(sLocation.getBatchCi());
						outStorageTp.setSAmount(ysAmount);
						outStorageTp.setRealAmount(sLocation.getStockNum());
						outStorageTp.setLocation(sLocation.getSLocationNo());
						outStorageTpService.save(outStorageTp);

						//移除当前库位信息
						sLocationList.remove(sLocation);
						if(sLocationList.size() == 0){
							break;
						}

					}

				}

				//如果电商区的货品不够就从立库区补
				if(outAmountLeft > 0){

					for(SLocation sLocation : sLocationLKList){

						//原始发货数
						int ysAmount = outStorageItem.getAmount();

						if(outAmountLeft < sLocation.getStockNum()){
							//减去占用库存数
							sLocation.setStockNum(sLocation.getStockNum() - outAmountLeft);
							outStorageTp.setUniqueCode(sLocation.getTrayNo());
							outStorageTp.setItemId(sLocation.getBatchCi());
							outStorageTp.setSAmount(ysAmount);
							outStorageTp.setLocation(sLocation.getSLocationNo());
							outStorageTp.setRealAmount(outAmountLeft);
							outStorageTpService.save(outStorageTp);
							break;

						}else if(outAmountLeft == sLocation.getStockNum()){

							//减去占用库存数
							sLocation.setStockNum(0);
							outStorageTp.setUniqueCode(sLocation.getTrayNo());
							outStorageTp.setItemId(sLocation.getBatchCi());
							outStorageTp.setSAmount(ysAmount);
							outStorageTp.setRealAmount(outAmountLeft);
							outStorageTp.setLocation(sLocation.getSLocationNo());
							outStorageTpService.save(outStorageTp);

							//移除当前库位信息
							sLocationList.remove(sLocation);
							break;

						}else{

							//减去占用库存数
							sLocation.setStockNum(sLocation.getStockNum() - outAmountLeft);
							outStorageTp.setUniqueCode(sLocation.getTrayNo());
							outStorageTp.setItemId(sLocation.getBatchCi());
							outStorageTp.setSAmount(ysAmount);
							outStorageTp.setRealAmount(sLocation.getStockNum());
							outStorageTp.setLocation(sLocation.getSLocationNo());
							outStorageTpService.save(outStorageTp);

							outAmountLeft = outAmountLeft - sLocation.getStockNum();

							//移除当前库位信息
							sLocationList.remove(sLocation);

						}

					}

				}

			}

		}

	}

	private void fenpeiDSTPInfo(List<String> dianshangOuts, Map<String, List<SLocation>> usedDSSlocationForSku) {

		for(String DSOut : dianshangOuts){

			OutStorage outStorage = this.getById(DSOut);

			//获取出库单的行项目
			List<OutStorageItem> outStorageItemList = outStorageItemService.list(
					Wrappers.<OutStorageItem>query().lambda().eq(OutStorageItem::getWmsBillNo, outStorage.getWmsBillNo()));

			for(OutStorageItem outStorageItem : outStorageItemList) {

				//行项目应发数量
				int outAmount = outStorageItem.getAmount();
				String sku = outStorageItem.getSku();
				int outAmountLeft = outAmount;

				//获取此sku相关的库位信息
				List<SLocation> sLocationList =  usedDSSlocationForSku.get(sku);


				OutStorageTp outStorageTp = new OutStorageTp();
				outStorageTp.setWmsBillNo(outStorageItem.getWmsBillNo());
				outStorageTp.setOutStorageItemId(outStorageItem.getOutStorageItemId());
				outStorageTp.setSku(sku);
				outStorageTp.setOperator(SecurityUtils.getUser().getUsername());

				for(SLocation sLocation : sLocationList){

					//原始库存数
					int ysAmount = outStorageItem.getAmount();

					if(outAmount < sLocation.getStockNum()){

						//减去占用库存数
						sLocation.setStockNum(sLocation.getStockNum() - outAmount);
						outStorageTp.setUniqueCode(sLocation.getTrayNo());
						outStorageTp.setItemId(sLocation.getBatchCi());
						outStorageTp.setSAmount(ysAmount);
						outStorageTp.setRealAmount(outAmount);
						outStorageTp.setLocation(sLocation.getSLocationNo());
						outStorageTpService.save(outStorageTp);
						break;

					}else if(outAmountLeft == sLocation.getStockNum()){

						//减去占用库存数
						sLocation.setStockNum(outStorageItem.getAmount() - outAmountLeft);
						outStorageTp.setUniqueCode(sLocation.getTrayNo());
						outStorageTp.setItemId(sLocation.getBatchCi());
						outStorageTp.setSAmount(ysAmount);
						outStorageTp.setRealAmount(outAmountLeft);
						outStorageTp.setLocation(sLocation.getSLocationNo());
						outStorageTpService.save(outStorageTp);

						//移除当前库位信息
						sLocationList.remove(sLocation);
						break;

					}else{

						//减去占用库存数
						sLocation.setStockNum(outStorageItem.getAmount() - outAmountLeft);
						outStorageTp.setUniqueCode(sLocation.getTrayNo());
						outStorageTp.setItemId(sLocation.getBatchCi());
						outStorageTp.setSAmount(ysAmount);
						outStorageTp.setRealAmount(outAmountLeft);
						outStorageTp.setLocation(sLocation.getSLocationNo());
						outStorageTpService.save(outStorageTp);
						outAmountLeft = outAmountLeft - sLocation.getStockNum();
						//移除当前库位信息
						sLocationList.remove(sLocation);

					}

				}

			}

		}
	}

	private String createPackageForOut(List<String> dianshangOuts,String initStatus) {
		LocalDateTime timeNow = LocalDateTime.now();

		DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyyMMdd");

		String ymd = dtf.format(timeNow);

		int randomInt = RandomUtil.randomInt(1000, 9999);

		String preWmsNo = "BCCKC";

		String packageNO = preWmsNo + ymd + randomInt;

		this.update(Wrappers.<OutStorage>update().lambda().set(OutStorage::getPackageNo,packageNO).set(OutStorage::getPackageStatus,initStatus)
				.in(OutStorage::getOutPageNo,dianshangOuts));

		return packageNO;
	}

	private void createSubPackageAndInfoForDSOut(String packageNo,List<String> dianshangOuts,
												 Map<String,List<SLocation>> usedDSSlocationForSku) {

		boolean isOneItem = "1".equals(this.getById(dianshangOuts.get(0)).getIsOneItem());


		if(isOneItem){

			//如果是单品规出库单，数量多的sku先出库
			List<Map.Entry<String, List<SLocation>>> list = sortMapEntriesForDSOne(usedDSSlocationForSku);

			createSubPackagesAndInfo(packageNo, list,dianshangOuts,isOneItem);


		}else{
			//如果是多品规出库单，数量少的sku先出库
			List<Map.Entry<String, List<SLocation>>> list = sortMapEntriesForDSMore(usedDSSlocationForSku);

			createSubPackagesAndInfo(packageNo, list,dianshangOuts,isOneItem);

		}

	}

	private void createSubPackagesAndInfo(String packageNo, List<Map.Entry<String, List<SLocation>>> list,
										   List<String> dianshangOuts,boolean isOneItem) {
		List<SLocation> sLocationList = new ArrayList<>();

		//组合所有需要发货的库位信息
		for(Map.Entry<String,List<SLocation>> mapping:list){

			sLocationList.addAll(mapping.getValue());
		}

		//计算所需子波次数量
		int subPackageNum = Double.valueOf(Math.ceil(sLocationList.size()/lQuantity)).intValue();

		List<SubPackageInfo> subPackageInfos = new ArrayList<>();

		for (int i = 0; i< subPackageNum; i++){

			SubPackage subPackage = new SubPackage();
			subPackage.setSubPackageNo(packageNo+"_"+i);
			subPackage.setPackageNo(packageNo);
			if(i==0){
				subPackage.setStatus("1");
			}else{
				subPackage.setStatus("0");
			}
			subPackageService.save(subPackage);

			for(int j = 0; j< lQuantity; j++){

				int fromSlocationIndex = Double.valueOf(lQuantity).intValue()*i+j;

				if(fromSlocationIndex > sLocationList.size()-1){

					break;

				}
				SubPackageInfo subPackageInfo = new SubPackageInfo();
				subPackageInfo.setSubPackageNo(subPackage.getSubPackageNo());
				SLocation sLocation =
						sLocationService.getOne(Wrappers.<SLocation>query().lambda().eq(SLocation::getAreaId,"10")
								.eq(SLocation::getIsUsed,"0")
								.eq(SLocation::getLocationStatus,"1").eq(SLocation::getStatus,"1")
								.orderByAsc(SLocation::getSOrder).last("limit 1"));
				subPackageInfo.setLLocation(sLocation.getSLocationNo());
				//更新L区库位状态
				sLocation.setIsUsed("1");
				sLocation.setUpdateTime(LocalDateTime.now());
				sLocationService.updateById(sLocation);
				subPackageInfo.setFromLocation(sLocationList.get(fromSlocationIndex).getSLocationNo());
				subPackageInfo.setTrayNo(sLocationList.get(fromSlocationIndex).getTrayNo());
				subPackageInfo.setSku(sLocationList.get(fromSlocationIndex).getSku());
				subPackageInfo.setTrayAmount(sLocationList.get(fromSlocationIndex).getStockNum());
				subPackageInfo.setRealAmount(sLocationList.get(fromSlocationIndex).getOutAmount());
				subPackageInfoService.save(subPackageInfo);
				subPackageInfos.add(subPackageInfo);
			}
		}

		//处理小车和订单的信息
		//多品规出库单按时间倒排序,单品规出库单按sku数量多的正序

		if(isOneItem){

			Collections.sort(dianshangOuts, new Comparator<String>() {
				@Override
				public int compare(String o1, String o2) {

					OutStorage outStorage1 = OutStorageServiceImpl.super.getById(o1);

					OutStorage outStorage2 = OutStorageServiceImpl.super.getById(o2);

					//获取出库单的行项目
					List<OutStorageItem> outStorageItemList1 = outStorageItemService.list(
							Wrappers.<OutStorageItem>query().lambda().eq(OutStorageItem::getWmsBillNo, outStorage1.getWmsBillNo()));

					List<OutStorageItem> outStorageItemList2 = outStorageItemService.list(
							Wrappers.<OutStorageItem>query().lambda().eq(OutStorageItem::getWmsBillNo,
									outStorage2.getWmsBillNo()));

					Integer skuNum1 = outStorageItemList1.get(0).getAmount();

					Integer skuNum2 = outStorageItemList2.get(0).getAmount();

					return skuNum1.compareTo(skuNum2);
				}
			});

		}else{

			Collections.sort(dianshangOuts, new Comparator<String>() {
				@Override
				public int compare(String o1, String o2) {

					OutStorage outStorage1 = OutStorageServiceImpl.super.getById(o1);

					OutStorage outStorage2 = OutStorageServiceImpl.super.getById(o2);

					return outStorage1.getCreateTime().compareTo(outStorage2.getCreateTime());
				}
			});
		}


		double cartOQ = cartOrderQuantity;

		int cartNum = Double.valueOf(Math.ceil(dianshangOuts.size()/cartOQ)).intValue();

		for(int i = 0; i< cartNum; i++){

			for(int j = 0; j < cartOrderQuantity; j++){

				if((cartOrderQuantity*i + j) > dianshangOuts.size()-1){

					break;

				}

				String outNo = dianshangOuts.get(cartOrderQuantity*i + j);

				OutStorage outStorage = this.getById(outNo);

				//获取出库单的行项目
				List<OutStorageItem> outStorageItemList = outStorageItemService.list(
						Wrappers.<OutStorageItem>query().lambda().eq(OutStorageItem::getWmsBillNo, outStorage.getWmsBillNo()));

				for(OutStorageItem outStorageItem : outStorageItemList){

					CartInfo cartInfo = new CartInfo();

					cartInfo.setWmsBillNo(outStorage.getWmsBillNo());
					cartInfo.setOutStorageItemId(outStorageItem.getOutStorageItemId());
					cartInfo.setSku(outStorageItem.getSku());
					cartInfo.setCartId(i+1);
					for(SubPackageInfo subPackageInfo : subPackageInfos){

						if(outStorageItem.getSku().equals(subPackageInfo.getSku())){

							if(subPackageInfo.getRealAmount() == 0){

								continue;

							}

							if(subPackageInfo.getRealAmount() > outStorageItem.getAmount()){

								cartInfo.setJhNum(outStorageItem.getAmount());
								cartInfo.setJhLocation(subPackageInfo.getToLocation());
								cartInfoService.save(cartInfo);

								subPackageInfo.setRealAmount(subPackageInfo.getRealAmount() - outStorageItem.getAmount());

							}else{

								cartInfo.setJhNum(subPackageInfo.getRealAmount());
								cartInfo.setJhLocation(subPackageInfo.getToLocation());
								cartInfoService.save(cartInfo);

								subPackageInfo.setRealAmount(0);
							}
						}
					}

				}

			}

		}

	}

	private List<Map.Entry<String, List<SLocation>>> sortMapEntriesForDSMore(
			Map<String, List<SLocation>> usedDSSlocationForSku) {
		//多品规订单sku数量排序
		List<Map.Entry<String,List<SLocation>>> list = new ArrayList<Map.Entry<String,List<SLocation>>>(usedDSSlocationForSku.entrySet());
		Collections.sort(list,new Comparator<Map.Entry<String,List<SLocation>>>() {
			//升序排序
			@Override
			public int compare(Map.Entry<String, List<SLocation>> o1,
							   Map.Entry<String, List<SLocation>> o2) {
				Integer q1 = 0;
				Integer q2 = 0;

				for(SLocation sLocation : o1.getValue()){
					q1 = q1 + sLocation.getOutAmount();
				}

				for(SLocation sLocation : o2.getValue()){
					q2 = q2 + sLocation.getOutAmount();
				}

				return q1.compareTo(q2);
			}

		});

		for(Map.Entry<String,List<SLocation>> mapping:list){
			log.info("出库顺序是:"+mapping.getKey()+":"+mapping.getValue());
		}
		return list;
	}

	private List<Map.Entry<String, List<SLocation>>> sortMapEntriesForDSOne(
			Map<String, List<SLocation>> usedDSSlocationForSku) {
		//单品规订单sku数量排序
		List<Map.Entry<String,List<SLocation>>> list = new ArrayList<Map.Entry<String,List<SLocation>>>(usedDSSlocationForSku.entrySet());
		Collections.sort(list,new Comparator<Map.Entry<String,List<SLocation>>>() {
			//升序排序
			@Override
			public int compare(Map.Entry<String, List<SLocation>> o1,
							   Map.Entry<String, List<SLocation>> o2) {
				Integer q1 = 0;
				Integer q2 = 0;

				for(SLocation sLocation : o1.getValue()){
					q1 = q1 + sLocation.getStockNum();
				}

				for(SLocation sLocation : o2.getValue()){
					q2 = q2 + sLocation.getStockNum();
				}

				return q2.compareTo(q1);
			}

		});

		for(Map.Entry<String,List<SLocation>> mapping:list){
			log.info("出库顺序是:"+mapping.getKey()+":"+mapping.getValue());
		}
		return list;
	}

	//从电商区计算库存
	private boolean stockAmountFromDS(Map<String, Integer> skuAmount, Map<String, Integer> skuAmountBH,
									  Map<String,List<SLocation>> usedDSSlocationForSku) {
		boolean needBH = false;
		for(String sku : skuAmount.keySet()){
			int outAmount = skuAmount.get(sku);
			//剩余出库数量
			int amountLeft = outAmount;

			List<SLocation> outLocationInfos = new ArrayList<>();

			while(true){

				//查找电商区的已使用的空框加货物的激活的
				SLocation sLocation =
						sLocationService.getOne(Wrappers.<SLocation>query().lambda().eq(SLocation::getAreaId,"2").eq(SLocation::getIsUsed,"1")
								.eq(SLocation::getLocationStatus,"5").eq(SLocation::getStatus,"1").eq(SLocation::getSku,sku)
								.orderByAsc(SLocation::getSOrder).last("limit 1"));

				if(sLocation == null){
					needBH = true;
					skuAmountBH.put(sku,amountLeft);
					break;
				}
				if(amountLeft <= sLocation.getStockNum()){
					sLocation.setOutAmount(amountLeft);
					outLocationInfos.add(sLocation);
					usedDSSlocationForSku.put(sku,outLocationInfos);
					sLocation.setIsUsed("2");
					sLocation.setUpdateTime(LocalDateTime.now());
					sLocationService.updateById(sLocation);
					break;
				}else{
					amountLeft = amountLeft - sLocation.getStockNum();
					sLocation.setOutAmount(sLocation.getStockNum());
					outLocationInfos.add(sLocation);
					usedDSSlocationForSku.put(sku,outLocationInfos);
					sLocation.setIsUsed("2");
					sLocation.setUpdateTime(LocalDateTime.now());
					sLocationService.updateById(sLocation);
				}
			}

		}
		return needBH;
	}

	//计算电商订单库存总数
	private void sumStockAmount(List<String> dianshangOuts, Map<String, Integer> skuAmount) {

		for(String DSOut : dianshangOuts){

			OutStorage outStorage = this.getById(DSOut);

			//获取出库单的行项目
			List<OutStorageItem> outStorageItemList = outStorageItemService.list(
					Wrappers.<OutStorageItem>query().lambda().eq(OutStorageItem::getWmsBillNo, outStorage.getWmsBillNo()));

			for(OutStorageItem outStorageItem : outStorageItemList){

				int outAmount = outStorageItem.getAmount();
				String sku = outStorageItem.getSku();

				//如果统计中有次sku就把出库数量相加
				if(skuAmount.get(sku) == null){
					skuAmount.put(sku,outAmount);
				}else{

					int outAmountPlus = outAmount + skuAmount.get(sku);
					skuAmount.put(sku,outAmountPlus);
				}

			}

		}
	}

	//从立库区查找补货的库存
	private boolean stockAmountFromLK(Map<String, Integer> skuAmountBH,
									  Map<String,List<SLocation>> usedLKSlocation) {
		boolean canPackage = true;
		for(String sku : skuAmountBH.keySet()){
			int outAmount = skuAmountBH.get(sku);
			//剩余出库数量
			int amountLeft = outAmount;

			List<SLocation> outLocationInfos = new ArrayList<>();

			while(true){

				//查找立库区的已使用的空框加货物的激活的
				SLocation sLocation =
						sLocationService.getOne(Wrappers.<SLocation>query().lambda().eq(SLocation::getAreaId,"1").eq(SLocation::getIsUsed,"1")
								.eq(SLocation::getStatus,"1").eq(SLocation::getSku,sku)
								.orderByAsc(SLocation::getSOrder).last("limit 1"));

				if(sLocation == null){
					canPackage = false;
					break;
				}
				if(amountLeft <= sLocation.getStockNum()){
					outLocationInfos.add(sLocation);
					usedLKSlocation.put(sku,outLocationInfos);
					sLocation.setIsUsed("2");
					sLocation.setUpdateTime(LocalDateTime.now());
					sLocationService.updateById(sLocation);
					break;
				}else{
					amountLeft = amountLeft - sLocation.getStockNum();
					outLocationInfos.add(sLocation);
					usedLKSlocation.put(sku,outLocationInfos);
					sLocation.setIsUsed("2");
					sLocation.setUpdateTime(LocalDateTime.now());
					sLocationService.updateById(sLocation);
				}
			}

		}
		return canPackage;
	}

	private void saveOutTp(OutStorageItem outStorageItem, SLocation sLocation) {

		OutStorageTp outStorageTp = new OutStorageTp();
		outStorageTp.setWmsBillNo(outStorageItem.getWmsBillNo());
		outStorageTp.setOutStorageItemId(outStorageItem.getOutStorageItemId());
		outStorageTp.setUniqueCode(sLocation.getTrayNo());
		outStorageTp.setSku(outStorageItem.getSku());
		outStorageTp.setItemId(sLocation.getBatchCi());
		outStorageTp.setSAmount(sLocation.getStockNum());
		outStorageTp.setLocation(sLocation.getSLocationNo());

		outStorageTpService.save(outStorageTp);
	}


	@Override
	public PackageDetailForVO getPackageDetail(String packageNo) {

		PackageDetailForVO packageDetailForVO = new PackageDetailForVO();
		OutStorage outStorage = this.getOne(Wrappers.<OutStorage>query().lambda().eq(OutStorage::getPackageNo,
				packageNo).last("limit 1"));
		packageDetailForVO.setPackageNo(outStorage.getPackageNo());
		packageDetailForVO.setPackageStatus(outStorage.getPackageStatus());


		List<SubPackage> subPackages = subPackageService.list(Wrappers.<SubPackage>query().lambda()
				.eq(SubPackage::getPackageNo, packageNo));

		List<SubPackageForVO> subPackageForVOS = new ArrayList<>();

		for(SubPackage subPackage : subPackages){

			SubPackageForVO subPackageForVO = new SubPackageForVO();
			subPackageForVO.setSubPackageNo(subPackage.getSubPackageNo());
			subPackageForVO.setSubPackageStatus(subPackage.getStatus());

			subPackageForVOS.add(subPackageForVO);
		}
		packageDetailForVO.setSubPackageForVOS(subPackageForVOS);

		List<OutStorage> outStorageList = this.list(Wrappers.<OutStorage>query().lambda().eq(OutStorage::getPackageNo,
				packageNo));
		List<OutAndOOutForPackage> outAndOOutForPackages = new ArrayList<>();

		for(OutStorage outStorage1 : outStorageList){

			OutAndOOutForPackage outAndOOutForPackage = new OutAndOOutForPackage();
			outAndOOutForPackage.setOutPageNo(outStorage1.getOutPageNo());
			outAndOOutForPackage.setWmsBillNo(outStorage1.getWmsBillNo());
			outAndOOutForPackage.setStatus(outStorage1.getStatus());

			outAndOOutForPackages.add(outAndOOutForPackage);
		}

		packageDetailForVO.setOutAndOOutForPackages(outAndOOutForPackages);

		return packageDetailForVO;
	}

	@Override
	public OutItemForVO getOutDetail(String outPageNo) {

		OutItemForVO outItemForVO = new OutItemForVO();

		//获取出库单头信息
		OutStorage outStorage = this.getById(outPageNo);

		outItemForVO.setOutPageNo(outStorage.getOutPageNo());
		outItemForVO.setWmsBillNo(outStorage.getWmsBillNo());
		outItemForVO.setPackageNo(outStorage.getPackageNo());
		outItemForVO.setVehicleInformation(outStorage.getVehicleInformation());
        outItemForVO.setLocationNo(outStorage.getLocationNo());

        //获取出库单item信息
		List<OutStorageItem> outStorageItems =
				outStorageItemService.list(Wrappers.<OutStorageItem>query().lambda().eq(OutStorageItem::getWmsBillNo,
						outStorage.getWmsBillNo()));

		Map<OutDetailForVO, List<OutTPDetailForVO>>  detailTp = new HashMap<>();

		for(OutStorageItem outStorageItem : outStorageItems){

			OutDetailForVO outDetailForVO = new OutDetailForVO();

			Sku sku = skuService.getById(outStorageItem.getSku());

			outDetailForVO.setOutItemId(outStorageItem.getOutStorageItemId());
			outDetailForVO.setSku(outStorageItem.getSku());
			outDetailForVO.setSkuName(sku.getGdname());
			outDetailForVO.setAmount(outStorageItem.getAmount());
			outDetailForVO.setUnit(sku.getUnit());
			outDetailForVO.setBatchNo(outStorageItem.getBatchNo());

			List<OutTPDetailForVO> outTPDetailForVOList = new ArrayList<>();

			List<OutStorageTp> outStorageTps =
					outStorageTpService.list(Wrappers.<OutStorageTp>query().lambda().eq(OutStorageTp::getOutStorageItemId,
							outStorageItem.getOutStorageItemId()));

			for(OutStorageTp outStorageTp : outStorageTps){

				OutTPDetailForVO outTPDetailForVO = new OutTPDetailForVO();

				outTPDetailForVO.setTpNo(outStorageTp.getUniqueCode());
				outTPDetailForVO.setUnit(sku.getUnit());
				outTPDetailForVO.setStockNo(outStorageTp.getSAmount());
				outTPDetailForVO.setRealAmount(outStorageTp.getRealAmount()==null?0:outStorageTp.getRealAmount());
				outTPDetailForVO.setStatus(outStorageTp.getStatus());
				outTPDetailForVO.setOperator(outStorageTp.getOperator());
				outTPDetailForVOList.add(outTPDetailForVO);
			}

			detailTp.put(outDetailForVO,outTPDetailForVOList);

		}

		outItemForVO.setOutTps(detailTp);

		return outItemForVO;
	}

	@Override
	public OutTPForPDAVO getOutTPDetailForPDA(String uniqueCode) {

		OutTPForPDAVO outTPForPDAVO = new OutTPForPDAVO();

		TraySku traySku = traySkuService.getById(uniqueCode);

		Sku sku = skuService.getById(traySku.getSku());

		InStorage inStorage = inStorageMapper.selectById(traySku.getInPageNo());

		InStorageItem inStorageItem = inStorageItemService.getById(traySku.getInStorageItemId());

		OutStorageTp outStorageTp = outStorageTpService.getOne(Wrappers.<OutStorageTp>query().lambda()
				.eq(OutStorageTp::getUniqueCode,uniqueCode).eq(OutStorageTp::getStatus,"0").last("limit 1"));

		OutStorage outStorage = this.getOne(Wrappers.<OutStorage>query().lambda()
				.eq(OutStorage::getWmsBillNo,outStorageTp.getWmsBillNo()));


		outTPForPDAVO.setSku(traySku.getSku());
		outTPForPDAVO.setSkuName(sku.getGdname());
		outTPForPDAVO.setStockNo(traySku.getStockNum());
		outTPForPDAVO.setMustAmount(traySku.getMustNum());
		outTPForPDAVO.setRealAmount(traySku.getMustNum());
		outTPForPDAVO.setInTime(inStorage.getInDate());
		outTPForPDAVO.setBatchCi(traySku.getBatchCi());
		outTPForPDAVO.setBatchNo(inStorageItem.getBatchNo());
		outTPForPDAVO.setPrdTime(inStorageItem.getProductDate());
		outTPForPDAVO.setEffTime(inStorageItem.getEffDate());
		outTPForPDAVO.setCarInf(outStorage.getVehicleInformation());
		outTPForPDAVO.setLocation(outStorage.getLocationNo());
		outTPForPDAVO.setUniqueCode(traySku.getTrayNo());

		return outTPForPDAVO;
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void submitOutDetail(OutDetailForPDADTO outDetailForPDADTO) {

		OutStorageTp outStorageTp = outStorageTpService.getOne(Wrappers.<OutStorageTp>query().lambda()
		.eq(OutStorageTp::getUniqueCode,outDetailForPDADTO.getTpNo()).eq(OutStorageTp::getStatus,"0"));

		outStorageTp.setRealAmount(outDetailForPDADTO.getRealAmount());
		outStorageTp.setOperator(SecurityUtils.getUser().getUsername());
		outStorageTp.setStatus("2");
		outStorageTpService.updateById(outStorageTp);

		OutStorageItem outStorageItem =
				outStorageItemService
						.getOne(Wrappers.<OutStorageItem>query().lambda().eq(OutStorageItem::getOutStorageItemId,
								outStorageTp.getOutStorageItemId()));

		OutStorage outStorage =
				this.getOne(Wrappers.<OutStorage>query().lambda().eq(OutStorage::getWmsBillNo,
						outStorageItem.getWmsBillNo()));


//		OutStorage outStorage = this.getOne(Wrappers.<OutStorage>query().lambda()
//				.eq(OutStorage::getWmsBillNo,outStorageTp.getWmsBillNo()));

		List<OutStorageTp> outStorageTpList = outStorageTpService.list(Wrappers.<OutStorageTp>query().lambda()
		.eq(OutStorageTp::getWmsBillNo,outStorageTp.getWmsBillNo()));

		List<B2bTaskRecord> b2bTaskRecords = b2bTaskRecordService.list(Wrappers.<B2bTaskRecord>query().lambda()
		.eq(B2bTaskRecord::getWmsBillNo,outStorageTp.getWmsBillNo()));

		if(outStorageTpList.size()-1 == b2bTaskRecords.size()){

			//如果是出库单中最后一个托盘，就清空临时出库托盘信息 并更新出库单状态为已完成
			b2bTaskRecordService.remove(Wrappers.<B2bTaskRecord>query().lambda()
					.eq(B2bTaskRecord::getWmsBillNo,outStorageTp.getWmsBillNo()));
			outStorage.setStatus("3");
			outStorage.setPackageStatus("3");
			this.updateById(outStorage);

			//回调ERP：下架回调接口
			log.info("调用ERP下架回调开始...这是最后一个托盘 回传orderStatus 1和行项目");
			ERPOutStorageDTO erpOutStorageDTO = new ERPOutStorageDTO();
			DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

			List<OutStorageItem> outStorageItemList =
					outStorageItemService.list(Wrappers.<OutStorageItem>query().lambda().eq(OutStorageItem::getOutStorageItemId,
									outStorageTp.getOutStorageItemId()));

			List<ERPOutStorageItemDTO> erpOutStorageItemDTOS = new ArrayList<>();
			for(OutStorageItem outStorageItemForErp : outStorageItemList){
				ERPOutStorageItemDTO erpOutStorageItemDTO = new ERPOutStorageItemDTO();

				List<OutStorageTp> outStorageTpListForItem =
						outStorageTpService.list(Wrappers.<OutStorageTp>query().lambda()
								.eq(OutStorageTp::getOutStorageTpId,outStorageTp.getOutStorageTpId()));

				List<ERPOutStorageTpDTO> erpOutStorageTpDTOList = new ArrayList<>();

				for(OutStorageTp outStorageTpForERP : outStorageTpListForItem){

					ERPOutStorageTpDTO erpOutStorageTpDTO = new ERPOutStorageTpDTO();
					BeanUtils.copyProperties(outStorageTpForERP, erpOutStorageTpDTO);
					erpOutStorageTpDTO.setAmount(outStorageTpForERP.getRealAmount());
					erpOutStorageTpDTOList.add(erpOutStorageTpDTO);

				}
				erpOutStorageItemDTO.setErpOutStorageTpDTOList(erpOutStorageTpDTOList);

				BeanUtils.copyProperties(outStorageItemForErp, erpOutStorageItemDTO);

				erpOutStorageItemDTOS.add(erpOutStorageItemDTO);
			}
			erpOutStorageDTO.setErpOutStorageItemDTOList(erpOutStorageItemDTOS);
			BeanUtils.copyProperties(outStorage, erpOutStorageDTO);

			String  outDateStr = outStorage.getOutDate().format(formatter);
			erpOutStorageDTO.setOutDate(outDateStr);
			erpOutStorageDTO.setOrderStatus("1");
			try{
				erpCallBackService.callBackOut(erpOutStorageDTO);
				log.info("调用ERP下架回调完成。");

			}catch (Exception e){
				log.error("调用ERP下架回调出现异常！"+e.getMessage());
				e.printStackTrace();
			}

		}else{
			B2bTaskRecord b2bTaskRecord = new B2bTaskRecord();
			b2bTaskRecord.setWmsBillNo(outStorageTp.getWmsBillNo());
			b2bTaskRecord.setOutTpId(outStorageTp.getOutStorageTpId());
			b2bTaskRecord.setTpNo(outDetailForPDADTO.getTpNo());
			b2bTaskRecord.setSku(outStorageTp.getSku());
			Sku sku = skuService.getById(outStorageTp.getSku());
			b2bTaskRecord.setSkuName(sku.getGdname());
			b2bTaskRecord.setRealAmount(outDetailForPDADTO.getRealAmount());
			b2bTaskRecord.setOperator(SecurityUtils.getUser().getUsername());

			b2bTaskRecordService.save(b2bTaskRecord);
			//出库中
			outStorage.setStatus("2");
			this.updateById(outStorage);

			//回调ERP：下架回调接口
			log.info("调用ERP下架回调开始...这不是最后一个托盘 回传orderStatus 0和行项目");
			ERPOutStorageDTO erpOutStorageDTO = new ERPOutStorageDTO();
			DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

			List<OutStorageItem> outStorageItemList =
					outStorageItemService.list(Wrappers.<OutStorageItem>query().lambda().eq(OutStorageItem::getOutStorageItemId,
							outStorageTp.getOutStorageItemId()));

			List<ERPOutStorageItemDTO> erpOutStorageItemDTOS = new ArrayList<>();
			for(OutStorageItem outStorageItemForErp : outStorageItemList){
				ERPOutStorageItemDTO erpOutStorageItemDTO = new ERPOutStorageItemDTO();

				List<OutStorageTp> outStorageTpListForItem =
						outStorageTpService.list(Wrappers.<OutStorageTp>query().lambda()
								.eq(OutStorageTp::getOutStorageTpId,outStorageTp.getOutStorageTpId()));

				List<ERPOutStorageTpDTO> erpOutStorageTpDTOList = new ArrayList<>();

				for(OutStorageTp outStorageTpForERP : outStorageTpListForItem){

					ERPOutStorageTpDTO erpOutStorageTpDTO = new ERPOutStorageTpDTO();
					BeanUtils.copyProperties(outStorageTpForERP, erpOutStorageTpDTO);
					erpOutStorageTpDTO.setAmount(outStorageTpForERP.getRealAmount());
					erpOutStorageTpDTOList.add(erpOutStorageTpDTO);

				}
				erpOutStorageItemDTO.setErpOutStorageTpDTOList(erpOutStorageTpDTOList);

				BeanUtils.copyProperties(outStorageItemForErp, erpOutStorageItemDTO);

				erpOutStorageItemDTOS.add(erpOutStorageItemDTO);
			}
			erpOutStorageDTO.setErpOutStorageItemDTOList(erpOutStorageItemDTOS);
			BeanUtils.copyProperties(outStorage, erpOutStorageDTO);

			String  outDateStr = outStorage.getOutDate().format(formatter);
			erpOutStorageDTO.setOutDate(outDateStr);
			erpOutStorageDTO.setOrderStatus("0");
			try{
				erpCallBackService.callBackOut(erpOutStorageDTO);
				log.info("调用ERP下架回调完成。");

			}catch (Exception e){
				log.error("调用ERP下架回调出现异常！"+e.getMessage());
				e.printStackTrace();
			}

		}

	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void emptyTPReturnForPDA(String fromLocation,String tpno) {

		//获取启用的叠盘区未使用的排序级别最高的库位编号
		SLocation sLocationDP =
				sLocationService.getOne(Wrappers.<SLocation>query().lambda().eq(SLocation::getStatus, 1)
						.eq(SLocation::getAreaId, 11).eq(SLocation::getIsUsed, 0).eq(SLocation::getLocationStatus,"1")
						.orderByAsc(SLocation::getSOrder).last("limit 1"));
		if(sLocationDP == null){
			throw new RuntimeException("未找到叠盘区位置信息,抛出异常!!!");
		}

		//调用WCS AtoB的接口  fromLocation  sLocationDP
		WCSInvInDTO wcsInvInDTO = new WCSInvInDTO();
		String taskId = "wmstrx" + LocalDateTime.now()
				.format(DateTimeFormatter.ofPattern(DatePattern.PURE_DATETIME_MS_PATTERN));
		wcsInvInDTO.setTaskId(taskId);
		wcsInvInDTO.setTaskSource("11");
		wcsInvInDTO.setLocatorFrom(fromLocation);
		wcsInvInDTO.setInloc(sLocationDP.getSLocationNo());
		wcsInvInDTO.setStockNo(tpno);
		wcsInvInDTO.setMemoInfo1("wms调用wcs入库接口,托盘返回叠盘机");

		if(!wcsWmsTrxService.handleWCSInvIn(wcsInvInDTO)){
			throw new RuntimeException("调用WCS入库接口异常!!!");
		}

		log.info("wms调用wcs入库接口,托盘返回叠盘机 from:"+fromLocation+"to:"+sLocationDP.getSLocationNo()+"托盘编号:"+tpno);

		WcsWmsTrx wcsWmsTrx = new WcsWmsTrx();
		wcsWmsTrx.setWmsTrxId(taskId);
		wcsWmsTrx.setTrxType("11");
		wcsWmsTrx.setFromLocation(fromLocation);
		wcsWmsTrx.setToLocation(sLocationDP.getSLocationNo());
		wcsWmsTrx.setTrayNo(tpno);
		wcsWmsTrxMapper.insert(wcsWmsTrx);

		//清除托盘和货品信息
		traySkuService.removeById(tpno);

	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void tpReturnForPDA(TPReturnForPDADTO tpReturnForPDADTO) {

		TraySku traySku = traySkuService.getById(tpReturnForPDADTO.getTpNo());
		traySku.setStockNum(traySku.getStockNum() - tpReturnForPDADTO.getRealAmount());
		traySku.setUpdateTime(LocalDateTime.now());
		traySkuService.updateById(traySku);

		log.info("托盘返库提交 这是需要返库的托盘 先释放返库库区库位 traySku 托盘编号是：" + tpReturnForPDADTO.getTpNo());

		//找出返库立库库位位置
		SLocation sLocationFrom =
				sLocationService.getOne(Wrappers.<SLocation>query().lambda().eq(SLocation::getSLocationNo,
						traySku.getSLocationNo()));
		//释放库位
		sLocationFrom.setTrayNo(null);
		sLocationFrom.setBatchNo("");
		sLocationFrom.setBatchCi("");
		sLocationFrom.setSku(null);
		sLocationFrom.setHuozId(null);
		sLocationFrom.setRealHuoz(null);
		sLocationFrom.setStockNum(0);
		sLocationFrom.setOutAmount(0);
		sLocationFrom.setIsUsed("0");
		sLocationFrom.setLocationStatus("1");
		sLocationFrom.setInPageNo("");
		sLocationFrom.setInStorageItemId(0);
		sLocationFrom.setUpdateTime(LocalDateTime.now());
		//更新库位信息
		sLocationService.updateById(sLocationFrom);
		log.info("已释放" + sLocationFrom.getSLocationNo() + "库位");

		//检查库区情况是否释放库区
		StockArea stockAreaOld = stockAreaService.getById(sLocationFrom.getStockAreaNo());

		log.info("检查" + stockAreaOld.getStockAreaNo() + "库区是否可以释放");
		log.info("检查" + stockAreaOld.getStockAreaNo() + "库区是否有location_status=4的情况");
		List<SLocation> sLocationList =
				sLocationService.list(Wrappers.<SLocation>query().lambda().eq(SLocation::getStockAreaNo,
								stockAreaOld.getStockAreaNo())
						.eq(SLocation::getIsUsed, "1")
						.eq(SLocation::getLocationStatus, "4")
						.eq(SLocation::getStatus, "1"));
		log.info("检查结果:有" + sLocationList.size() + "个");

		log.info("检查" + stockAreaOld.getStockAreaNo() + "库区是否有is_used=2的情况,正在使用中的");
		List<SLocation> sLocationListUsing =
				sLocationService.list(Wrappers.<SLocation>query().lambda().eq(SLocation::getStockAreaNo,
								stockAreaOld.getStockAreaNo())
						.eq(SLocation::getIsUsed, "2")
						.eq(SLocation::getStatus, "1"));

		log.info("检查结果:有" + sLocationListUsing.size() + "个");

		sLocationList.addAll(sLocationListUsing);

		if (sLocationList.size() == 0) {

			stockAreaOld.setInBillNumber("");
			stockAreaOld.setBatchNo("");
			stockAreaOld.setSku(null);
			stockAreaOld.setStatus("0");
			stockAreaOld.setLockStatus("0");
			stockAreaService.updateById(stockAreaOld);
			log.info(stockAreaOld.getStockAreaNo() + "库区没有找到正在使用有托盘货物并激活的库位，已经释放库区");
		} else {
			log.info(stockAreaOld.getStockAreaNo() + "库区找到正在使用有托盘货物并激活的库位，不可以释放");
		}

		log.info("处理库区查找是否使用ERP盘点后的inbillnumber");
		ERPCheckFeedback erpCheckFeedback = erpCheckFeedbackService.getOne(Wrappers.<ERPCheckFeedback>query().lambda()
				.eq(ERPCheckFeedback::getItemId, traySku.getBatchCi())
				.eq(ERPCheckFeedback::getUniqueCode, traySku.getTrayNo())
				.orderByDesc(ERPCheckFeedback::getCreateTime).last("limit 1"));

		InStorageItem inStorageItem;
		InStorage instorage;

		if(null != erpCheckFeedback){
			log.info("查出在ERP盘点反馈中有此托盘信息，创建虚拟入库单保存inbillnumber");
			//虚拟入库单和行项目
			InStorage inStorageNew = new InStorage();
			inStorageNew.setInBillNumber(erpCheckFeedback.getInBillNumber());
			instorage = inStorageNew;

			InStorageItem inStorageItemNew = new InStorageItem();
			inStorageItemNew.setSku(erpCheckFeedback.getConfirmSku());
			inStorageItemNew.setBatchNo(erpCheckFeedback.getConfirmBatchNo());
			inStorageItem = inStorageItemNew;

		}else{
			//重新入库
			//获取入库单信息
			log.info("没有查出在ERP盘点反馈中有此托盘信息，查询原始入库单信息 获取库区");
			inStorageItem = inStorageItemService.getById(traySku.getInStorageItemId());

			instorage = inStorageService.getById(traySku.getInPageNo());
		}

		StockArea stockAreaNew = null;
		try {
			stockAreaNew = inStorageService.getStockArea(inStorageItem, instorage, "10");
		} catch (Exception e) {
			log.error("获取库区出现异常。。。");
			e.printStackTrace();
			throw new RuntimeException("查找库区出现异常，返库异常!!!");
		}

		if (null == stockAreaNew) {
			log.error("获取库区出现异常。。。没找到库区");
			throw new RuntimeException("返库异常!!!");
		}
		//获取启用的立库区未使用的排序级别最高的库位编号
		SLocation sLocation =
				sLocationService.getOne(Wrappers.<SLocation>query().lambda().eq(SLocation::getStatus, 1)
						.eq(SLocation::getAreaId, 1).eq(SLocation::getIsUsed, 0)
						.eq(SLocation::getLocationStatus, "1")
						.eq(SLocation::getStockAreaNo, stockAreaNew.getStockAreaNo())
						.orderByAsc(SLocation::getSOrder).last("limit 1"));

		if (sLocation == null) {

			throw new RuntimeException("返库异常!!!");

		} else {

			String sNo = sLocation.getSLocationNo();
			sLocation.setIsUsed("2");
			sLocation.setUpdateTime(LocalDateTime.now());
			sLocationService.updateById(sLocation);

			//更新库区状态 先检查是否符合预占用状态
			boolean yzyStatus = stockAreaService.checkStockAreaYuZhanYong(stockAreaNew.getStockAreaNo());

			if (yzyStatus) {

				//更新库区为预占用状态
				StockArea stockAreaForCheck = stockAreaService.getById(sLocation.getStockAreaNo());
				stockAreaForCheck.setSku(stockAreaForCheck.getSku());
				stockAreaForCheck.setLockStatus("2");
				stockAreaService.updateById(stockAreaForCheck);
				log.info("更新库区为预占用状态,库区:" + sLocation.getStockAreaNo());

			} else {
				log.info("库区不符合预占用状态,按原来逻辑更新库区信息:" + sLocation.getStockAreaNo());
				//查找此库位所属库区是否有可使用的库位 判断是否锁定库区
				log.info("回库检查库区状态,查找此库位所属库区是否有可使用的库位,库区:" + sLocation.getStockAreaNo());
				SLocation sLocationForCheck =
						sLocationService.getOne(Wrappers.<SLocation>query().lambda().eq(SLocation::getStatus, 1)
								.eq(SLocation::getAreaId, 1).eq(SLocation::getIsUsed, 0)
								.eq(SLocation::getStockAreaNo, sLocation.getStockAreaNo())
								.eq(SLocation::getLocationStatus, "1")
								.orderByAsc(SLocation::getSOrder).last("limit 1"));
				if (null == sLocationForCheck) {
					//如果没有可使用的库位，更新库区为锁定状态
					StockArea stockAreaForCheck = stockAreaService.getById(sLocation.getStockAreaNo());
					stockAreaForCheck.setSku(stockAreaForCheck.getSku());
					stockAreaForCheck.setStatus("2");
					stockAreaForCheck.setLockStatus("1");
					stockAreaService.updateById(stockAreaForCheck);
					log.info("没有可使用的库位，更新库区为锁定状态,库区:" + sLocation.getStockAreaNo());
				} else {

					//如果有可使用的库位，更新库区为未锁定状态
					StockArea stockAreaForCheck = stockAreaService.getById(sLocation.getStockAreaNo());
					stockAreaForCheck.setSku(stockAreaForCheck.getSku());
					stockAreaForCheck.setStatus("1");
					stockAreaForCheck.setLockStatus("0");
					stockAreaService.updateById(stockAreaForCheck);
					log.info("有可使用的库位，更新库区为未锁定状态,库区:" + sLocation.getStockAreaNo());

				}
			}

			//调用wcs做回库
			WCSInvInDTO wcsInvInDTO = new WCSInvInDTO();
			String taskId = "wmstrx" + LocalDateTime.now()
					.format(DateTimeFormatter.ofPattern(DatePattern.PURE_DATETIME_MS_PATTERN));
			wcsInvInDTO.setTaskId(taskId);
			wcsInvInDTO.setTaskSource("10");
			wcsInvInDTO.setLocatorFrom(tpReturnForPDADTO.getFromLocation());
			wcsInvInDTO.setInloc(sNo);
			wcsInvInDTO.setStockNo(tpReturnForPDADTO.getTpNo());
			wcsInvInDTO.setMemoInfo1("wms调用wcs做返库");
			wcsInvInDTO.setMemoInfo2(stockAreaNew.getStockAreaNo());

			if (!wcsWmsTrxService.handleWCSInvIn(wcsInvInDTO)) {
				throw new RuntimeException("调用WCS入库接口异常!!!");
			}

			WcsWmsTrx wcsWmsTrx = new WcsWmsTrx();
			wcsWmsTrx.setWmsTrxId(taskId);
			wcsWmsTrx.setTrxType("10");
			wcsWmsTrx.setTrayNo(tpReturnForPDADTO.getTpNo());
			wcsWmsTrx.setFromLocation(tpReturnForPDADTO.getFromLocation());
			wcsWmsTrx.setToLocation(sNo);

			wcsWmsTrxService.save(wcsWmsTrx);
		}

		//old
//		TraySku traySku = traySkuService.getById(tpReturnForPDADTO.getTpNo());
//		traySku.setStockNum(traySku.getStockNum()-tpReturnForPDADTO.getRealAmount());
//		traySku.setUpdateTime(LocalDateTime.now());
//		traySkuService.updateById(traySku);
//
//		//先把返库的库位占用标记成正在使用
//		SLocation sLocation = sLocationService.getById(traySku.getSLocationNo());
//		sLocation.setIsUsed("2");
//		sLocation.setUpdateTime(LocalDateTime.now());
//		sLocationService.updateById(sLocation);
//
//		//调用wcs重新入库
//		WCSInvInDTO wcsInvInDTO = new WCSInvInDTO();
//		String taskId = "wmstrx" + LocalDateTime.now()
//				.format(DateTimeFormatter.ofPattern(DatePattern.PURE_DATETIME_MS_PATTERN));
//		wcsInvInDTO.setTaskId(taskId);
//		wcsInvInDTO.setTaskSource("10");
//		wcsInvInDTO.setLocatorFrom(tpReturnForPDADTO.getFromLocation());
//		wcsInvInDTO.setInloc(traySku.getSLocationNo());
//		wcsInvInDTO.setStockNo(tpReturnForPDADTO.getTpNo());
//		wcsInvInDTO.setMemoInfo1("wms调用wcs入库接口,重新入库");
//
//		if(!wcsWmsTrxService.handleWCSInvIn(wcsInvInDTO)){
//			throw new RuntimeException("调用WCS入库接口异常!!!");
//		}
//
//
//		WcsWmsTrx wcsWmsTrx = new WcsWmsTrx();
//		wcsWmsTrx.setWmsTrxId(taskId);
//		wcsWmsTrx.setTrxType("10");
//		wcsWmsTrx.setFromLocation(tpReturnForPDADTO.getFromLocation());
//		wcsWmsTrx.setToLocation(traySku.getSLocationNo());
//		wcsWmsTrx.setTrayNo(tpReturnForPDADTO.getTpNo());
//		wcsWmsTrxMapper.insert(wcsWmsTrx);
	}

	@Override
	public List<PackageListForDSVO> getPackageListForDS() {

		List<OutStorage> outStorageList = this.list(Wrappers.<OutStorage>query().lambda()
				.eq(OutStorage::getOutType,"2").and(wrapper ->wrapper.eq(OutStorage::getPackageStatus,"0")
				.or().eq(OutStorage::getPackageStatus,"1").or().eq(OutStorage::getPackageStatus,"2")));

		List<PackageListForDSVO> packageListForDSVOS = new ArrayList<>();

		for(OutStorage outStorage : outStorageList){
			PackageListForDSVO packageListForDSVO = new PackageListForDSVO();

			packageListForDSVO.setPackageNo(outStorage.getPackageNo());
			packageListForDSVO.setPackageStatus(outStorage.getPackageStatus());

			packageListForDSVOS.add(packageListForDSVO);
		}

		return packageListForDSVOS;
	}

	@Override
	public boolean getPackageTaskForDS() {

		List<OutStorage> outStorageTaskList = this.list(Wrappers.<OutStorage>query().lambda()
				.eq(OutStorage::getOutType, "2").eq(OutStorage::getTaskId, "0")
				.eq(OutStorage::getOperator,SecurityUtils.getUser().getUsername()).last("limit 1"));

		if(outStorageTaskList != null && outStorageTaskList.size() > 0){

			return false;

		}

		List<OutStorage> outStorageList = this.list(Wrappers.<OutStorage>query().lambda()
				.eq(OutStorage::getOutType, "2").eq(OutStorage::getStatus, "1").last("limit 10"));

		if(outStorageList.isEmpty() || outStorageList == null ){

			return false;

		}

		List<String> outs = new ArrayList<>();

		for(OutStorage outStorage : outStorageList){

			outs.add(outStorage.getOutPageNo());

		}

		return  this.update(Wrappers.<OutStorage>update().lambda().set(OutStorage::getOperator,
				SecurityUtils.getUser().getUsername()).set(OutStorage::getTaskId, "0")
				.in(OutStorage::getOutPageNo, outs));
	}

	@Override
	public List<OutStorage> listPackageTaskForDS() {

		List<OutStorage> outStorageList = this.list(Wrappers.<OutStorage>query().lambda()
		.eq(OutStorage::getOperator,SecurityUtils.getUser().getUsername())
				.eq(OutStorage::getTaskId,"0"));

		return outStorageList;
	}

	@Override
	public List<OutStorageTpForDS> listPackageTaskDetailForDS(String wmsBillNo) {

		List<OutStorageTp> outStorageTps = outStorageTpService.list(Wrappers.<OutStorageTp>query().lambda()
		.eq(OutStorageTp::getWmsBillNo,wmsBillNo));

		List<OutStorageTpForDS> outStorageTpForDSList = new ArrayList<>();

		for(OutStorageTp outStorageTp : outStorageTps){

			OutStorageTpForDS outStorageTpForDS = new OutStorageTpForDS();
			outStorageTpForDS.setWmsBillNo(outStorageTp.getWmsBillNo());
			outStorageTpForDS.setLocation(outStorageTp.getLocation());
			outStorageTpForDS.setSku(outStorageTp.getSku());
			Sku sku = skuService.getById(outStorageTp.getSku());
			outStorageTpForDS.setSkuName(sku.getGdname());
			outStorageTpForDS.setAmount(outStorageTp.getSAmount());
			outStorageTpForDS.setUnit(sku.getUnit());

			outStorageTpForDSList.add(outStorageTpForDS);

		}

		return outStorageTpForDSList;
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public boolean submitPackageTaskDetailForDS(String wmsBillNo) {

		List<OutStorageTp> outStorageTpList =  outStorageTpService.list(Wrappers.<OutStorageTp>query().lambda()
		.eq(OutStorageTp::getWmsBillNo,wmsBillNo));

		for(OutStorageTp outStorageTp : outStorageTpList){

			outStorageTp.setOperator(SecurityUtils.getUser().getUsername());
			outStorageTp.setStatus("2");

			outStorageTpService.updateById(outStorageTp);

			//更新库存
			SLocation sLocation = sLocationService.getById(outStorageTp.getLocation());
			sLocation.setStockNum(sLocation.getStockNum() - outStorageTp.getRealAmount());
			sLocation.setUpdateTime(LocalDateTime.now());
			sLocationService.updateById(sLocation);

		}

		//更新出库单状态为已完成
		this.update(Wrappers.<OutStorage>update().lambda().set(OutStorage::getStatus,"3")
				.set(OutStorage::getTaskId,"1").eq(OutStorage::getWmsBillNo,wmsBillNo));

		OutStorage outStorage = this.getOne(Wrappers.<OutStorage>query().lambda()
		.eq(OutStorage::getWmsBillNo,wmsBillNo));

		List<OutStorage> outStorageList = this.list(Wrappers.<OutStorage>query().lambda()
		.eq(OutStorage::getPackageNo,outStorage.getPackageNo()));

		//检查波次单中所有出库单是否都已完成
		boolean isDone = true;
		for(OutStorage outStorage1 : outStorageList){

			if(!"3".equals(outStorage1.getStatus())){

				isDone = false;

			}

		}

		if(isDone){

			//更新波次单状态为已完成
			this.update(Wrappers.<OutStorage>update().lambda().set(OutStorage::getPackageStatus,"3")
					.eq(OutStorage::getWmsBillNo,wmsBillNo));

		}else{

			//更新波次单状态为出库中
			this.update(Wrappers.<OutStorage>update().lambda().set(OutStorage::getPackageStatus,"2")
					.eq(OutStorage::getWmsBillNo,wmsBillNo));

		}

		return true;
	}

	@Override
	public OutBHTPForPDAVO getOutBHTPDetailForPDA(String subPackageNo,String uniqueCode) {

		OutBHTPForPDAVO outBHTPForPDAVO = new OutBHTPForPDAVO();

//		BhTMP bhTMP = bhTMPService.getOne(Wrappers.<BhTMP>query().lambda().eq(BhTMP::getTpNo,uniqueCode)
//		.eq(BhTMP::getDel,"0"));

		SubPackageInfo subpackageInfo = subPackageInfoService.getOne(Wrappers.<SubPackageInfo>query().lambda()
				.eq(SubPackageInfo::getTrayNo,uniqueCode).eq(SubPackageInfo::getSubPackageNo,subPackageNo));

//		OutStorageTp outStorageTp =
//				outStorageTpService.getOne(Wrappers.<OutStorageTp>query().lambda().eq(OutStorageTp::getUniqueCode,
//				uniqueCode).eq(OutStorageTp::getStatus,"0"));

		TraySku traySku = traySkuService.getById(uniqueCode);

		InStorageItem inStorageItem = inStorageItemService.getById(traySku.getInStorageItemId());

		outBHTPForPDAVO.setSku(subpackageInfo.getSku());
		Sku sku = skuService.getById(subpackageInfo.getSku());
		outBHTPForPDAVO.setSkuName(sku.getGdname());
		outBHTPForPDAVO.setUniqueCode(subpackageInfo.getTrayNo());
		outBHTPForPDAVO.setStockNo(subpackageInfo.getTrayAmount());
		outBHTPForPDAVO.setRealAmount(subpackageInfo.getRealAmount());
		outBHTPForPDAVO.setOutTime(subpackageInfo.getCreateTime());
		outBHTPForPDAVO.setBatchCi(traySku.getBatchCi());
		outBHTPForPDAVO.setPrdTime(inStorageItem.getProductDate());
		outBHTPForPDAVO.setEffTime(inStorageItem.getEffDate());
		outBHTPForPDAVO.setLLocation(subpackageInfo.getLLocation());

		return outBHTPForPDAVO;
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void submitBHOutDetail(OutDetailForPDABHDTO outBHDetailForPDADTO) {

		//更新出库单托盘信息的出库库位编号
//		OutStorageTp outStorageTp =
//				outStorageTpService.getOne(Wrappers.<OutStorageTp>query().lambda()
//						.eq(OutStorageTp::getUniqueCode,outBHDetailForPDADTO.getTpNo())
//				.eq(OutStorageTp::getStatus,"0"));
//
//		outStorageTp.setLocation(outBHDetailForPDADTO.getLocation());
//		outStorageTp.setOperator(SecurityUtils.getUser().getUsername());
//		outStorageTpService.updateById(outStorageTp);

		//更新补货临时表信息
//		BhTMP bhTMP = bhTMPService.getOne(Wrappers.<BhTMP>query().lambda()
//				.eq(BhTMP::getTpNo,outBHDetailForPDADTO.getTpNo())
//				.eq(BhTMP::getStatus,"0").eq(BhTMP::getDel,"0"));
//		bhTMP.setOperator(SecurityUtils.getUser().getUsername());
//		bhTMP.setStatus("1");
//		bhTMPService.updateById(bhTMP);
//		//更新波次单状态
//		List<BhTMP> bhTMPS = bhTMPService.list(Wrappers.<BhTMP>query().lambda()
//				.eq(BhTMP::getPackageNo,bhTMP.getPackageNo()));
//
//		boolean bhDone = true;
//
//		for(BhTMP bhTMP1 : bhTMPS){
//
//			if("0".equals(bhTMP1.getStatus())){
//				bhDone = false;
//				break;
//			}
//		}
//		if(bhDone){
//			bhTMPService.update(Wrappers.<BhTMP>update().lambda().set(BhTMP::getDel,"1").eq(BhTMP::getPackageNo,
//					bhTMP.getPackageNo()));
//			OutStorage outStorage = this.getOne(Wrappers.<OutStorage>query().lambda().eq(OutStorage::getWmsBillNo,
//					outStorageTp.getWmsBillNo()));
//			outStorage.setPackageStatus("0");
//			this.updateById(outStorage);
//		}

		//更新提总补货临时表信息
		SubPackageInfo subPackageInfo = subPackageInfoService.getOne(Wrappers.<SubPackageInfo>query().lambda()
				.eq(SubPackageInfo::getSubPackageNo,outBHDetailForPDADTO.getSubPackageNo())
				.eq(SubPackageInfo::getTrayNo,outBHDetailForPDADTO.getTpNo()).eq(SubPackageInfo::getStatus,"0"));

		subPackageInfo.setToLocation(outBHDetailForPDADTO.getTZlocation());
		subPackageInfo.setStatus("1");
		subPackageInfoService.updateById(subPackageInfo);

		//更新小车拣货信息
		List<CartInfo> cartInfos = cartInfoService.list(Wrappers.<CartInfo>query().lambda()
				.eq(CartInfo::getSku,subPackageInfo.getSku()).eq(CartInfo::getStatus,"0")
				.isNull(CartInfo::getJhLocation));

		int skuNum = subPackageInfo.getRealAmount();

		for(CartInfo cartInfo : cartInfos){

			cartInfo.setJhLocation(subPackageInfo.getToLocation());
			cartInfo.setSubPackageNo(subPackageInfo.getSubPackageNo());
			cartInfoService.updateById(cartInfo);
			skuNum = skuNum - cartInfo.getJhNum();
			if(skuNum <= 0){
				break;
			}
		}

		//更新子波次单状态
		List<SubPackageInfo> spis = subPackageInfoService.list(Wrappers.<SubPackageInfo>query().lambda()
				.eq(SubPackageInfo::getSubPackageNo,outBHDetailForPDADTO.getSubPackageNo()));

		boolean bhDone = true;

		for(SubPackageInfo subPackageInfo1 : spis){

			if("0".equals(subPackageInfo1.getStatus())){
				bhDone = false;
				break;
			}
		}
		//子波次都提总完成
		if(bhDone){
			subPackageService.update(Wrappers.<SubPackage>update().lambda().set(SubPackage::getStatus,"2")
					.eq(SubPackage::getSubPackageNo,outBHDetailForPDADTO.getSubPackageNo()));

			boolean subPackALLDone = true;

			SubPackage subPackage = subPackageService.getOne(Wrappers.<SubPackage>query().lambda()
					.eq(SubPackage::getSubPackageNo,outBHDetailForPDADTO.getSubPackageNo())
							.last("limit 1"));

			List<SubPackage> sps = subPackageService.list(Wrappers.<SubPackage>query().lambda()
					.eq(SubPackage::getPackageNo,subPackage.getPackageNo()));

			for(SubPackage subPackage1 : sps){

				if("0".equals(subPackage1.getStatus())){
					subPackALLDone = false;
					break;
				}
			}

			if(subPackALLDone){

				this.update(Wrappers.<OutStorage>update().lambda().set(OutStorage::getStatus,"2")
						.eq(OutStorage::getPackageNo,subPackage.getPackageNo()));
			}

		}
	}

	@Override
	public void handleTJOuts(Map<String, ERPOutStorageDTO> erpOutStorageDTOMap) {

		for(String outPageNo : erpOutStorageDTOMap.keySet()){

			if(this.getById(outPageNo) != null){

				log.info("此T+出库单已经存在,处理下一个...");
				continue;
			}

			saveOut(erpOutStorageDTOMap.get(outPageNo),"CKB");

		}


	}

	@Override
	public List<SubPackage> listSubPackageForDS() {

		//查找正在提总补货中的波次单
		OutStorage outStorage =
				this.getOne(Wrappers.<OutStorage>query().lambda().eq(OutStorage::getPackageStatus,"1").eq(OutStorage::getOutType,
						"2").orderByAsc(OutStorage::getCreateTime).last("limit 1"));

		List<SubPackage> subPackages =
				subPackageService.list(Wrappers.<SubPackage>query().lambda().eq(SubPackage::getPackageNo,
						outStorage.getPackageNo()));

		return subPackages;
	}

	@Override
	public List<TiZongListForPDADTO> listTZDSSubPackageForPDA(String subPackageNo) {

        List<SubPackageInfo> subPackageInfos =
				subPackageInfoService.list(Wrappers.<SubPackageInfo>query().lambda()
						.eq(SubPackageInfo::getSubPackageNo, subPackageNo));

        List<TiZongListForPDADTO> tiZongListForPDADTOS = new ArrayList<>();

        for(SubPackageInfo subPackageInfo : subPackageInfos){

			TiZongListForPDADTO tiZongListForPDADTO = new TiZongListForPDADTO();
			tiZongListForPDADTO.setSubPackageNo(subPackageInfo.getSubPackageNo());
			tiZongListForPDADTO.setTrayNo(subPackageInfo.getTrayNo());
			tiZongListForPDADTO.setLLocation(subPackageInfo.getLLocation());
			Sku sku = skuService.getById(subPackageInfo.getSku());
			tiZongListForPDADTO.setSkuName(sku.getGdname());
			tiZongListForPDADTO.setStatus(subPackageInfo.getStatus());
			tiZongListForPDADTOS.add(tiZongListForPDADTO);
		}

		return tiZongListForPDADTOS;
	}

	@Override
	public List<SCart> listCartsSubPackageDSForPDA() {

		SubPackage subPackage = subPackageService.getOne(Wrappers.<SubPackage>query().lambda()
				.eq(SubPackage::getStatus, "2"));

		List<CartInfo> cartInfos = cartInfoService.list(Wrappers.<CartInfo>query().select("DISTINCT cart_id ").lambda()
				.eq(CartInfo::getSubPackageNo, subPackage.getSubPackageNo()));

		List<Integer> cartIds = new ArrayList<>();

		for(CartInfo cartInfo : cartInfos){
			cartIds.add(cartInfo.getCartId());
		}

		List<SCart> sCarts = sCartService.list(Wrappers.<SCart>query().lambda()
				.in(SCart::getId, cartIds));

		return sCarts;
	}

	@Override
	public List<PDADSOutStorageJHVO> listCartsDetailForPDA(String cartId) {

		List<CartInfo> cartInfos = cartInfoService.list(Wrappers.<CartInfo>query().lambda()
				.in(CartInfo::getCartId, cartId));

		List<SubPackageInfo> subPackageInfos = subPackageInfoService.list(Wrappers.<SubPackageInfo>query().lambda()
				.eq(SubPackageInfo::getSubPackageNo, cartInfos.get(0).getSubPackageNo()));

		//子波次包含的sku
		List<String> skus = new ArrayList<>();

		for(SubPackageInfo subPackageInfo:subPackageInfos){

			skus.add(subPackageInfo.getSku());

		}


		List<PDADSOutStorageJHVO> pdadsOutStorageJHVOS = new ArrayList<>();

		for(CartInfo cartInfo : cartInfos){

			PDADSOutStorageJHVO pdadsOutStorageJHVO = new PDADSOutStorageJHVO();

			OutStorage outStorage = this.getOne(Wrappers.<OutStorage>query().lambda()
					.eq(OutStorage::getWmsBillNo, cartInfo.getWmsBillNo()));

			pdadsOutStorageJHVO.setCartInfoId(cartInfo.getId());
			pdadsOutStorageJHVO.setOutPageNo(outStorage.getOutPageNo());
			pdadsOutStorageJHVO.setWmsBillNo(cartInfo.getWmsBillNo());
			pdadsOutStorageJHVO.setOutStorageItemId(cartInfo.getOutStorageItemId());
			pdadsOutStorageJHVO.setSubPackageNo(cartInfo.getSubPackageNo());
			pdadsOutStorageJHVO.setSku(cartInfo.getSku());
			Sku sku = skuService.getById(cartInfo.getSku());
			pdadsOutStorageJHVO.setSkuName(sku.getGdname());
			pdadsOutStorageJHVO.setAmount(cartInfo.getJhNum());
			pdadsOutStorageJHVO.setLocation(cartInfo.getJhLocation());
			pdadsOutStorageJHVO.setStatus(cartInfo.getStatus());
			if(skus.contains(cartInfo.getSku())){
				pdadsOutStorageJHVO.setGreen(true);
			}else{
				pdadsOutStorageJHVO.setGreen(false);
			}

			pdadsOutStorageJHVOS.add(pdadsOutStorageJHVO);
		}

		return pdadsOutStorageJHVOS;
	}

	@Override
	public List<Sku> listCartSKUsForPDA(String cartId) {

		List<CartInfo> cartInfos = cartInfoService.list(Wrappers.<CartInfo>query().lambda()
				.in(CartInfo::getCartId, cartId));

		List<SubPackageInfo> subPackageInfos = subPackageInfoService.list(Wrappers.<SubPackageInfo>query().lambda()
				.eq(SubPackageInfo::getSubPackageNo, cartInfos.get(0).getSubPackageNo()));

		//子波次包含的sku
		List<Sku> skus = new ArrayList<>();

		for(SubPackageInfo subPackageInfo:subPackageInfos){

			Sku sku = skuService.getById(subPackageInfo.getSku());

			skus.add(sku);

		}
		return skus;
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public boolean submitJHTaskForDS(String cartInfoId) {

		CartInfo cartInfo = cartInfoService.getById(cartInfoId);

		cartInfo.setStatus("1");

		boolean success = cartInfoService.updateById(cartInfo);

		if(success){

			List<CartInfo> cartInfos = cartInfoService.list(Wrappers.<CartInfo>query().lambda()
					.eq(CartInfo::getSubPackageNo, cartInfo.getSubPackageNo()));

			//检查子波次是否都已经拣货
			boolean JHALLDone = true;

			for(CartInfo cartInfo1 : cartInfos){
				if("0".equals(cartInfo1.getStatus())){

					JHALLDone = false;
					break;

				}
			}

			if(JHALLDone){

				//更新所有小车子波次为已完成
				cartInfoService.update(Wrappers.<CartInfo>update().lambda().set(CartInfo::getStatus,"2")
						.eq(CartInfo::getSubPackageNo,cartInfo.getSubPackageNo()));

				subPackageService.update(Wrappers.<SubPackage>update().lambda().set(SubPackage::getStatus,"3")
						.eq(SubPackage::getSubPackageNo,cartInfo.getSubPackageNo()));

			}

		}

		return success;
	}

	@Override
	public boolean getNextTZForDS(String packageNo) {

		SubPackage subPackage =
				subPackageService.getOne(Wrappers.<SubPackage>query().lambda().eq(SubPackage::getPackageNo,packageNo)
						.eq(SubPackage::getStatus, "1").or().eq(SubPackage::getStatus,"2")
						.orderByAsc(SubPackage::getCreateTime).last("limit 1"));

		if(subPackage != null){

			return false;
		}

		SubPackage subPackage1 =
				subPackageService.getOne(Wrappers.<SubPackage>query().lambda().eq(SubPackage::getPackageNo,packageNo)
						.eq(SubPackage::getStatus, "0")
						.orderByAsc(SubPackage::getCreateTime).last("limit 1"));

		if(subPackage1 != null){

			return false;
		}

		//激活下一个子波次
		subPackage1.setStatus("1");
		subPackageService.updateById(subPackage1);

		//通知wms运送货物,做电商提总补货
		callWCSForDSTZ();

		return true;
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public String handleAgvOut(String outPageNo) {
		synchronized (OutStorageServiceImpl.class){
			log.info("开始处理PDA备货出库请求，获取并锁定出库事务锁。。。出库单号为："+outPageNo);

		String message = null;
		OutStorage outStorageForBHOut = this.getById(outPageNo);
		//获取出库单月台位置
		String outLocationYT = outStorageForBHOut.getLocationNo();
		//获取出库单备货类型
		String bhlx = agvInQueueService.getOne(Wrappers.<AgvInQueue>query().lambda()
				.eq(AgvInQueue::getOutPageNo, outPageNo).last("limit 1")).getBhlx();

		//sku从小到大出库
		List<OutStorageItem> outStorageItemListForBHOut = outStorageItemService.list(Wrappers.<OutStorageItem>query().lambda()
				.eq(OutStorageItem::getWmsBillNo, outStorageForBHOut.getWmsBillNo()).orderByAsc(OutStorageItem::getSku)
				.orderByAsc(OutStorageItem::getBatchNo)
				.orderByAsc(OutStorageItem::getAmount));

		//出库单行项目数量小的先出
		for(OutStorageItem outStorageItem : outStorageItemListForBHOut){
			List<OutStorageTp> outStorageTpListForBHOut = outStorageTpService.list(Wrappers.<OutStorageTp>query().lambda()
					.eq(OutStorageTp::getWmsBillNo, outStorageItem.getWmsBillNo())
					.eq(OutStorageTp::getOutStorageItemId, outStorageItem.getOutStorageItemId())
					.orderByDesc(OutStorageTp::getRealAmount));
			//行项目托盘从大到小出库
			for(OutStorageTp outStorageTpForBH : outStorageTpListForBHOut){

				AgvInQueue agvInQueueForOut = agvInQueueService.getOne(Wrappers.<AgvInQueue>query().lambda()
						.eq(AgvInQueue::getTrayNo, outStorageTpForBH.getUniqueCode())
						.eq(AgvInQueue::getOutPageNo,outPageNo));
				AgvOutQueue agvOutQueueForOut = new AgvOutQueue();
				BeanUtils.copyProperties(agvInQueueForOut, agvOutQueueForOut);
				agvOutQueueForOut.setId(null);
				agvOutQueueForOut.setQueueStatus("0");
				agvOutQueueForOut.setOutLocation(outStorageForBHOut.getLocationNo());
				agvOutQueueForOut.setCreateTime(null);
				agvOutQueueForOut.setUpdateTime(null);
				agvOutQueueService.save(agvOutQueueForOut);
			}

		}
		log.info("已添加单出库单备货出库任务到agvout队列中");

		log.info("查询此出库单"+outPageNo+"的月台位置"+outLocationYT+"是否有要作业或者正在作业的任务，" +
				"如果有此出库单备货出库任务在队列中等待，如果没有就把第一sku和批次备货出库");
		AgvOutQueue agvOutQueueForCheck = agvOutQueueService.getOne(Wrappers.<AgvOutQueue>query().lambda()
				.eq(AgvOutQueue::getOutLocation, outLocationYT)
				.and(tmp->tmp.eq(AgvOutQueue::getQueueStatus, "2").or().eq(AgvOutQueue::getQueueStatus, "3"))
				.last("limit 1"));

		if(null != agvOutQueueForCheck){
			log.warn("月台"+outLocationYT+"正在使用，出库单备货出库任务在队列中等待。。。");
			message = "月台"+outLocationYT+"正在使用，出库单备货出库任务在队列中等待。。。";
			return message;
		}else{
			log.info(outLocationYT+"此月台没有备货出库正在作业的任务可以发送wcs备货出库指令");
			AgvOutQueue agvOutQueueForBHOutSku = agvOutQueueService.getOne(Wrappers.<AgvOutQueue>query().lambda()
					.eq(AgvOutQueue::getOutPageNo, outPageNo)
					.orderByAsc(AgvOutQueue::getId).last("limit 1"));
			List<AgvOutQueue> agvOutQueueForBHOut = agvOutQueueService.list(Wrappers.<AgvOutQueue>query().lambda()
					.eq(AgvOutQueue::getOutPageNo, outPageNo)
					.eq(AgvOutQueue::getSku,agvOutQueueForBHOutSku.getSku())
					.eq(AgvOutQueue::getBatchNo,agvOutQueueForBHOutSku.getBatchNo())
					.orderByAsc(AgvOutQueue::getId));

			agvBHOut(outStorageForBHOut, agvOutQueueForBHOut);

			message = "备货出库任务已下发wcs,出库单状态更新为<备货出库中>";
		}
			log.info("已处理完成PDA备货出库请求，正在释放出库事务锁。。。");
		return message;

		}
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void agvBHOut(OutStorage outStorageForBHOut, List<AgvOutQueue> agvOutQueueForBHOut) {
		//保存多个wcs出库接口参数,最后用另外一个线程触发
		List<WCSInvOutDTO> wcsInvOutDTOList = new ArrayList<>();

		for(AgvOutQueue agvOutQueue : agvOutQueueForBHOut){
			log.info("检查备货出库队列中任务托盘是否已经在AGV库位中，如果在就发送wcs指令，如果不在就继续等待");
			SLocation sLocationAGV = sLocationService.getOne(Wrappers.<SLocation>query().lambda()
					.eq(SLocation::getTrayNo,agvOutQueue.getTrayNo())
					.eq(SLocation::getAreaId,10)
					.eq(SLocation::getLocationStatus,"4"));
			if(null == sLocationAGV){
				log.info(agvOutQueue.getTrayNo()+"这个托盘还没有到达AGV备货区，出库任务置为等待3。。");
				agvOutQueue.setQueueStatus("3");
				agvOutQueue.setUpdateTime(LocalDateTime.now());
				agvOutQueueService.updateById(agvOutQueue);
			}else{
				log.info(agvOutQueue.getTrayNo()+"这个托盘已经到达AGV备货区");
				log.info(agvOutQueue.getTrayNo()+"锁定这个托盘所在的AGV备货区库位，准备wcs备货出库指令。。");
				sLocationAGV.setIsUsed("2");
				sLocationAGV.setUpdateTime(LocalDateTime.now());
				sLocationService.updateById(sLocationAGV);
				//agvSlocation中占用的库位发往wcs to月台
				WCSInvOutDTO wcsInvOutDTO = new WCSInvOutDTO();
				String taskId = "wmstrx" + LocalDateTime.now()
						.format(DateTimeFormatter.ofPattern(DatePattern.PURE_DATETIME_MS_PATTERN));
				wcsInvOutDTO.setTaskId(taskId);
				wcsInvOutDTO.setInvOutType("14");
				wcsInvOutDTO.setOutLoc(sLocationAGV.getSLocationNo());
				wcsInvOutDTO.setStockNo(sLocationAGV.getTrayNo());
				wcsInvOutDTO.setLocDesti(agvOutQueue.getOutLocation());
				wcsInvOutDTO.setMemoInfo1("wms调用wcs备货出库接口,to月台");
				wcsInvOutDTO.setMemoInfo2("AGV备货区");

				wcsInvOutDTOList.add(wcsInvOutDTO);

				WcsWmsTrx wcsWmsTrx = new WcsWmsTrx();
				wcsWmsTrx.setWmsTrxId(taskId);
				wcsWmsTrx.setTrxType("14");
				wcsWmsTrx.setFromLocation(sLocationAGV.getSLocationNo());
				wcsWmsTrx.setToLocation(agvOutQueue.getOutLocation());
				wcsWmsTrx.setTrayNo(agvOutQueue.getTrayNo());
				wcsWmsTrxMapper.insert(wcsWmsTrx);
				log.info("将AGV库位信息写入traysku临时托盘信息表中，准备扫码出库。");
				TraySku traySku = new TraySku();
				BeanUtils.copyProperties(sLocationAGV, traySku);
				traySku.setMustNum(sLocationAGV.getOutAmount());
				traySku.setSLocationNo(agvOutQueue.getSLocationNo());
				traySku.setCreateTime(null);
				traySku.setUpdateTime(null);
				traySkuService.save(traySku);

				//更新队列状态为正在作业
				agvOutQueue.setQueueStatus("2");
				agvOutQueue.setUpdateTime(LocalDateTime.now());
				agvOutQueueService.updateById(agvOutQueue);

			}

		}

		log.info("已添加多个AGVOUT队列任务,启动新线程调用wcs出库接口");

		OutCallWcsThread outCallWcsThread = new OutCallWcsThread(wcsInvOutDTOList,wcsWmsTrxService);
		outCallWcsThread.start();
		//更新备货信息
//		outStorageForBHOut.setStatus("8");
//		this.updateById(outStorageForBHOut);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void emptyTPforRG(String tpno) {

		//调用WCS AtoB的接口
		WCSEmptyCtlDTO wcsEmptyCtlDTO = new WCSEmptyCtlDTO();
		String taskId = "wmstrx" + LocalDateTime.now()
				.format(DateTimeFormatter.ofPattern(DatePattern.PURE_DATETIME_MS_PATTERN));
		wcsEmptyCtlDTO.setTaskId(taskId);
		wcsEmptyCtlDTO.setStockNo(tpno);

		if(!wcsWmsTrxService.handleWCSEmptyCtl(wcsEmptyCtlDTO)){
			throw new RuntimeException("调用WCS人工叠盘接口异常!!!");
		}

		log.info("wms调用wcs人工叠盘接口,托盘返回由人工处理 托盘编号:"+tpno);

		WcsWmsTrx wcsWmsTrx = new WcsWmsTrx();
		wcsWmsTrx.setWmsTrxId(taskId);
		wcsWmsTrx.setTrxType("18");
		wcsWmsTrx.setFromLocation(null);
		wcsWmsTrx.setToLocation(null);
		wcsWmsTrx.setTrayNo(tpno);
		wcsWmsTrxMapper.insert(wcsWmsTrx);

		//清除托盘和货品信息
		traySkuService.removeById(tpno);

	}
}
